diff --git a/CHANGES b/CHANGES index c8b59e9c5..503c1f8f0 100644 --- a/CHANGES +++ b/CHANGES @@ -30,6 +30,7 @@ Incompatible changes * html theme: Move a script tag for documentation_options.js in basic/layout.html to ``script_files`` variable * html theme: Move CSS tags in basic/layout.html to ``css_files`` variable +* #8915: html theme: Emit a warning for sphinx_rtd_theme-0.2.4 or older * #8508: LaTeX: uplatex becomes a default setting of latex_engine for Japanese documents * #5977: py domain: ``:var:``, ``:cvar:`` and ``:ivar:`` fields do not create @@ -38,6 +39,9 @@ Incompatible changes ``None`` by default instead of ``'default'`` * #8769: LaTeX refactoring: split sphinx.sty into multiple files and rename some auxiliary files created in ``latex`` build output repertory +* #8937: Use explicit title instead of +* #8487: The :file: option for csv-table directive now recognizes an absolute + path as a relative path from source directory Deprecated ---------- @@ -47,6 +51,8 @@ Deprecated * ``sphinx.directives.patches.CSVTable`` * ``sphinx.directives.patches.ListTable`` * ``sphinx.directives.patches.RSTTable`` +* ``sphinx.registry.SphinxComponentRegistry.get_source_input()`` +* ``sphinx.registry.SphinxComponentRegistry.source_inputs`` * ``sphinx.transforms.FigureAligner`` * ``sphinx.util.pycompat.convert_with_2to3()`` * ``sphinx.util.pycompat.execfile_()`` @@ -55,20 +61,34 @@ Deprecated Features added -------------- +* #8924: autodoc: Support ``bound`` argument for TypeVar +* #7549: autosummary: Enable :confval:`autosummary_generate` by default * #4826: py domain: Add ``:canonical:`` option to python directives to describe the location where the object is defined +* #7199: py domain: Add :confval:`python_use_unqualified_type_names` to suppress + the module name of the python reference if it can be resolved (experimental) * #7784: i18n: The alt text for image is translated by default (without :confval:`gettext_additional_targets` setting) * #2018: html: :confval:`html_favicon` and :confval:`html_logo` now accept URL for the image * #8070: html search: Support searching for 2characters word +* #8938: imgconverter: Show the error of the command availability check * #7830: Add debug logs for change detection of sources and templates * #8201: Emit a warning if toctree contains duplicated entries +* #8326: ``master_doc`` is now renamed to :confval:`root_doc` +* #8942: C++, add support for the C++20 spaceship operator, ``<=>``. +* #7199: A new node, ``sphinx.addnodes.pending_xref_condition`` has been added. + It can be used to choose appropriate content of the reference by conditions. Bugs fixed ---------- +* #8917: autodoc: Raises a warning if function has wrong __globals__ value +* #8415: autodoc: a TypeVar imported from other module is not resolved (in + Python 3.7 or above) +* #8905: html: html_add_permalinks=None and html_add_permalinks="" are ignored * #8380: html search: Paragraphs in search results are not identified as ``

`` +* #8915: html theme: The translation of sphinx_rtd_theme does not work * #8342: Emit a warning if a unknown domain is given for directive or role (ex. ``:unknown:doc:``) * #8711: LaTeX: backticks in code-blocks trigger latexpdf build warning (and font @@ -76,11 +96,20 @@ Bugs fixed * #8253: LaTeX: Figures with no size defined get overscaled (compared to images with size explicitly set in pixels) (fixed for ``'pdflatex'/'lualatex'`` only) * #8881: LaTeX: The depth of bookmarks panel in PDF is not enough for navigation +* #8925: LaTeX: 3.5.0 ``verbatimmaxunderfull`` setting does not work as + expected +* #8911: C++: remove the longest matching prefix in + :confval:`cpp_index_common_prefix` instead of the first that matches. +* C, properly reject function declarations when a keyword is used + as parameter name. +* #8933: viewcode: Failed to create back-links on parallel build +* #8960: C and C++, fix rendering of (member) function pointer types in + function parameter lists. Testing -------- -Release 3.5.2 (in development) +Release 3.5.3 (in development) ============================== Dependencies @@ -101,6 +130,16 @@ Bugs fixed Testing -------- +Release 3.5.2 (released Mar 06, 2021) +===================================== + +Bugs fixed +---------- + +* #8943: i18n: Crashed by broken translation messages in ES, EL and HR +* #8936: LaTeX: A custom LaTeX builder fails with unknown node error +* #8952: Exceptions raised in a Directive cause parallel builds to hang + Release 3.5.1 (released Feb 16, 2021) ===================================== @@ -164,6 +203,9 @@ Features added * #8775: autodoc: Support type union operator (PEP-604) in Python 3.10 or above * #8297: autodoc: Allow to extend :confval:`autodoc_default_options` via directive options +* #759: autodoc: Add a new configuration :confval:`autodoc_preserve_defaults` as + an experimental feature. It preserves the default argument values of + functions in source code and keep them not evaluated for readability. * #8619: html: kbd role generates customizable HTML tags for compound keys * #8634: html: Allow to change the order of JS/CSS via ``priority`` parameter for :meth:`Sphinx.add_js_file()` and :meth:`Sphinx.add_css_file()` diff --git a/MANIFEST.in b/MANIFEST.in index 1114ca19f..7c2f852a8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -15,6 +15,7 @@ include sphinx-quickstart.py include sphinx-apidoc.py include tox.ini include sphinx/locale/.tx/config +include sphinx/py.typed recursive-include sphinx/templates * recursive-include sphinx/texinputs * diff --git a/doc/_static/conf.py.txt b/doc/_static/conf.py.txt index 5420e2717..844451fd8 100644 --- a/doc/_static/conf.py.txt +++ b/doc/_static/conf.py.txt @@ -43,7 +43,7 @@ source_suffix = '.rst' # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +root_doc = 'index' # General information about the project. project = u'test' @@ -252,7 +252,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'test.tex', u'test Documentation', + (root_doc, 'test.tex', u'test Documentation', u'test', 'manual'), ] @@ -283,7 +283,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'test', u'test Documentation', + (root_doc, 'test', u'test Documentation', [author], 1) ] @@ -298,7 +298,7 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'test', u'test Documentation', + (root_doc, 'test', u'test Documentation', author, 'test', 'One line description of project.', 'Miscellaneous'), ] diff --git a/doc/conf.py b/doc/conf.py index 09397c76b..3eb01b5ea 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -9,7 +9,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', 'sphinx.ext.inheritance_diagram'] -master_doc = 'contents' +root_doc = 'contents' templates_path = ['_templates'] exclude_patterns = ['_build'] @@ -78,6 +78,7 @@ latex_show_urls = 'footnote' latex_use_xindy = True autodoc_member_order = 'groupwise' +autosummary_generate = False todo_include_todos = True extlinks = {'duref': ('http://docutils.sourceforge.net/docs/ref/rst/' 'restructuredtext.html#%s', ''), diff --git a/doc/development/tutorials/autodoc_ext.rst b/doc/development/tutorials/autodoc_ext.rst new file mode 100644 index 000000000..d8905710c --- /dev/null +++ b/doc/development/tutorials/autodoc_ext.rst @@ -0,0 +1,142 @@ +.. _autodoc_ext_tutorial: + +Developing autodoc extension for IntEnum +======================================== + +The objective of this tutorial is to create an extension that adds +support for new type for autodoc. This autodoc extension will format +the ``IntEnum`` class from Python standard library. (module ``enum``) + +Overview +-------- + +We want the extension that will create auto-documentation for IntEnum. +``IntEnum`` is the integer enum class from standard library ``enum`` module. + +Currently this class has no special auto documentation behavior. + +We want to add following to autodoc: + +* A new ``autointenum`` directive that will document the ``IntEnum`` class. +* The generated documentation will have all the enum possible values + with names. +* The ``autointenum`` directive will have an option ``:hex:`` which will + cause the integers be printed in hexadecimal form. + + +Prerequisites +------------- + +We need the same setup as in :doc:`the previous extensions `. This time, +we will be putting out extension in a file called :file:`autodoc_intenum.py`. +The :file:`my_enums.py` will contain the sample enums we will document. + +Here is an example of the folder structure you might obtain: + +.. code-block:: text + + └── source +    ├── _ext + │   └── autodoc_intenum.py +    ├── conf.py +    ├── index.rst +    └── my_enums.py + + +Writing the extension +--------------------- + +Start with ``setup`` function for the extension. + +.. literalinclude:: examples/autodoc_intenum.py + :language: python + :linenos: + :pyobject: setup + + +The :meth:`~Sphinx.setup_extension` method will pull the autodoc extension +because our new extension depends on autodoc. :meth:`~Sphinx.add_autodocumenter` +is the method that registers our new auto documenter class. + +We want to import certain objects from the autodoc extension: + +.. literalinclude:: examples/autodoc_intenum.py + :language: python + :linenos: + :lines: 1-7 + + +There are several different documenter classes such as ``MethodDocumenter`` +or ``AttributeDocumenter`` available in the autodoc extension but +our new class is the subclass of ``ClassDocumenter`` which a +documenter class used by autodoc to document classes. + +This is the definition of our new the auto-documenter class: + +.. literalinclude:: examples/autodoc_intenum.py + :language: python + :linenos: + :pyobject: IntEnumDocumenter + + +Important attributes of the new class: + +**objtype** + This attribute determines the ``auto`` directive name. In + this case the auto directive will be ``autointenum``. + +**directivetype** + This attribute sets the generated directive name. In + this example the generated directive will be ``.. :py:class::``. + +**priority** + the larger the number the higher is the priority. We want our + documenter be higher priority than the parent. + +**option_spec** + option specifications. We copy the parent class options and + add a new option *hex*. + + +Overridden members: + +**can_document_member** + This member is important to override. It should + return *True* when the passed object can be documented by this class. + +**add_directive_header** + This method generates the directive header. We add + **:final:** directive option. Remember to call **super** or no directive + will be generated. + +**add_content** + This method generates the body of the class documentation. + After calling the super method we generate lines for enum description. + + +Using the extension +------------------- + +You can now use the new autodoc directive to document any ``IntEnum``. + +For example, you have the following ``IntEnum``: + +.. code-block:: python + :caption: my_enums.py + + class Colors(IntEnum): + """Colors enumerator""" + NONE = 0 + RED = 1 + GREEN = 2 + BLUE = 3 + + +This will be the documentation file with auto-documentation directive: + +.. code-block:: rst + :caption: index.rst + + .. autointenum:: my_enums.Colors + + diff --git a/doc/development/tutorials/examples/autodoc_intenum.py b/doc/development/tutorials/examples/autodoc_intenum.py new file mode 100644 index 000000000..7fb85d066 --- /dev/null +++ b/doc/development/tutorials/examples/autodoc_intenum.py @@ -0,0 +1,52 @@ +from enum import IntEnum +from typing import Any, Optional + +from docutils.statemachine import StringList + +from sphinx.application import Sphinx +from sphinx.ext.autodoc import ClassDocumenter, bool_option + + +class IntEnumDocumenter(ClassDocumenter): + objtype = 'intenum' + directivetype = 'class' + priority = 10 + ClassDocumenter.priority + option_spec = dict(ClassDocumenter.option_spec) + option_spec['hex'] = bool_option + + @classmethod + def can_document_member(cls, + member: Any, membername: str, + isattr: bool, parent: Any) -> bool: + return isinstance(member, IntEnum) + + def add_directive_header(self, sig: str) -> None: + super().add_directive_header(sig) + self.add_line(' :final:', self.get_sourcename()) + + def add_content(self, + more_content: Optional[StringList], + no_docstring: bool = False + ) -> None: + + super().add_content(more_content, no_docstring) + + source_name = self.get_sourcename() + enum_object: IntEnum = self.object + use_hex = self.options.hex + self.add_line('', source_name) + + for enum_value in enum_object: + the_value_name = enum_value.name + the_value_value = enum_value.value + if use_hex: + the_value_value = hex(the_value_value) + + self.add_line( + f"**{the_value_name}**: {the_value_value}", source_name) + self.add_line('', source_name) + + +def setup(app: Sphinx) -> None: + app.setup_extension('sphinx.ext.autodoc') # Require autodoc extension + app.add_autodocumenter(IntEnumDocumenter) diff --git a/doc/development/tutorials/index.rst b/doc/development/tutorials/index.rst index be126b3ca..a7eee4899 100644 --- a/doc/development/tutorials/index.rst +++ b/doc/development/tutorials/index.rst @@ -13,3 +13,5 @@ Refer to the following tutorials to get started with extension development. helloworld todo recipe + autodoc_ext + diff --git a/doc/extdev/deprecated.rst b/doc/extdev/deprecated.rst index 828a73d05..96bc84ff3 100644 --- a/doc/extdev/deprecated.rst +++ b/doc/extdev/deprecated.rst @@ -32,11 +32,6 @@ The following is a list of deprecated interfaces. - TBD - ``logo_url`` - * - ``sphinx.directives.patches.CSVTable`` - - 4.0 - - 6.0 - - ``docutils.parsers.rst.diretives.tables.CSVTable`` - * - ``sphinx.directives.patches.ListTable`` - 4.0 - 6.0 @@ -47,6 +42,16 @@ The following is a list of deprecated interfaces. - 6.0 - ``docutils.parsers.rst.diretives.tables.RSTTable`` + * - ``sphinx.registry.SphinxComponentRegistry.get_source_input()`` + - 4.0 + - 6.0 + - N/A + + * - ``sphinx.registry.SphinxComponentRegistry.source_inputs`` + - 4.0 + - 6.0 + - N/A + * - ``sphinx.transforms.FigureAligner`` - 4.0 - 6.0 diff --git a/doc/extdev/nodes.rst b/doc/extdev/nodes.rst index e38393a78..3976de4c7 100644 --- a/doc/extdev/nodes.rst +++ b/doc/extdev/nodes.rst @@ -37,6 +37,7 @@ New inline nodes .. autoclass:: index .. autoclass:: pending_xref +.. autoclass:: pending_xref_condition .. autoclass:: literal_emphasis .. autoclass:: download_reference diff --git a/doc/man/sphinx-apidoc.rst b/doc/man/sphinx-apidoc.rst index 725d2f169..3ce5b4523 100644 --- a/doc/man/sphinx-apidoc.rst +++ b/doc/man/sphinx-apidoc.rst @@ -145,7 +145,7 @@ These options are used when :option:`--full` is specified: * ``module.rst_t`` * ``package.rst_t`` * ``toc.rst_t`` - * ``master_doc.rst_t`` + * ``root_doc.rst_t`` * ``conf.py_t`` * ``Makefile_t`` * ``Makefile.new_t`` diff --git a/doc/man/sphinx-quickstart.rst b/doc/man/sphinx-quickstart.rst index 520a420ce..16fc66560 100644 --- a/doc/man/sphinx-quickstart.rst +++ b/doc/man/sphinx-quickstart.rst @@ -72,7 +72,7 @@ Options .. option:: --master=MASTER - Master document name. (see :confval:`master_doc`). + Master document name. (see :confval:`root_doc`). .. rubric:: Extension Options @@ -149,7 +149,7 @@ Options sphinx project files generated by quickstart. Following Jinja2 template files are allowed: - * ``master_doc.rst_t`` + * ``root_doc.rst_t`` * ``conf.py_t`` * ``Makefile_t`` * ``Makefile.new_t`` diff --git a/doc/templating.rst b/doc/templating.rst index 97596e6a9..61b714bfa 100644 --- a/doc/templating.rst +++ b/doc/templating.rst @@ -325,7 +325,19 @@ in the future. .. data:: master_doc - The value of :confval:`master_doc`, for usage with :func:`pathto`. + Same as :data:`root_doc`. + + .. versionchanged:: 4.0 + + Renamed to ``root_doc``. + +.. data:: root_doc + + The value of :confval:`root_doc`, for usage with :func:`pathto`. + + .. versionchanged:: 4.0 + + Renamed from ``master_doc``. .. data:: pagename diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index de3416c47..989ce8737 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -183,11 +183,20 @@ General configuration .. confval:: master_doc - The document name of the "master" document, that is, the document that + Same as :confval:`root_doc`. + + .. versionchanged:: 4.0 + Renamed ``master_doc`` to ``master_doc``. + +.. confval:: root_doc + + The document name of the "root" document, that is, the document that contains the root :rst:dir:`toctree` directive. Default is ``'index'``. .. versionchanged:: 2.0 The default is changed to ``'index'`` from ``'contents'``. + .. versionchanged:: 4.0 + Renamed ``master_doc`` from ``master_doc``. .. confval:: exclude_patterns @@ -2023,8 +2032,8 @@ These options influence LaTeX output. *startdocname* String that specifies the :term:`document name` of the LaTeX file's master document. All documents referenced by the *startdoc* document in TOC trees - will be included in the LaTeX file. (If you want to use the default master - document for your LaTeX build, provide your :confval:`master_doc` here.) + will be included in the LaTeX file. (If you want to use the default root + document for your LaTeX build, provide your :confval:`root_doc` here.) *targetname* File name of the LaTeX file in the output directory. @@ -2293,7 +2302,7 @@ These options influence manual page output. String that specifies the :term:`document name` of the manual page's master document. All documents referenced by the *startdoc* document in TOC trees will be included in the manual file. (If you want to use the default - master document for your manual pages build, use your :confval:`master_doc` + root document for your manual pages build, use your :confval:`root_doc` here.) *name* @@ -2349,7 +2358,7 @@ These options influence Texinfo output. master document. All documents referenced by the *startdoc* document in TOC trees will be included in the Texinfo file. (If you want to use the default master document for your Texinfo build, provide your - :confval:`master_doc` here.) + :confval:`root_doc` here.) *targetname* File name (no extension) of the Texinfo file in the output directory. @@ -2705,6 +2714,17 @@ Options for the C++ domain .. versionadded:: 1.5 +Options for the Python domain +----------------------------- + +.. confval:: python_use_unqualified_type_names + + If true, suppress the module name of the python reference if it can be + resolved. The default is ``False``. + + .. versionadded:: 4.0 + + .. note:: This configuration is still in experimental Example of configuration file ============================= diff --git a/doc/usage/extensions/autodoc.rst b/doc/usage/extensions/autodoc.rst index f69ac8c5c..034c86e11 100644 --- a/doc/usage/extensions/autodoc.rst +++ b/doc/usage/extensions/autodoc.rst @@ -89,33 +89,96 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, Boil the noodle *time* minutes. - **Options and advanced usage** + .. rubric:: Options - * If you want to automatically document members, there's a ``members`` - option:: + .. rst:directive:option:: members + :type: no value or comma separated list + + If set, autodoc will generate document for the members of the target + module, class or exception. + + For example:: .. automodule:: noodle :members: - will document all module members (recursively), and :: + will document all module members (recursively), and :: .. autoclass:: Noodle :members: - will document all non-private member functions and properties (that is, - those whose name doesn't start with ``_``). + will document all class member methods and properties. - For modules, ``__all__`` will be respected when looking for members unless - you give the ``ignore-module-all`` flag option. Without - ``ignore-module-all``, the order of the members will also be the order in - ``__all__``. + By default, autodoc will not generate document for the members that are + private, not having docstrings, inherited from super class, or special + members. - You can also give an explicit list of members; only these will then be - documented:: + For modules, ``__all__`` will be respected when looking for members unless + you give the ``ignore-module-all`` flag option. Without + ``ignore-module-all``, the order of the members will also be the order in + ``__all__``. + + You can also give an explicit list of members; only these will then be + documented:: .. autoclass:: Noodle :members: eat, slurp + .. rst:directive:option:: undoc-members + :type: no value + + If set, autodoc will also generate document for the members not having + docstrings:: + + .. automodule:: noodle + :members: + :undoc-members: + + .. rst:directive:option:: private-members + :type: no value or comma separated list + + If set, autodoc will also generate document for the private members + (that is, those named like ``_private`` or ``__private``):: + + .. automodule:: noodle + :members: + :private-members: + + It can also take an explicit list of member names to be documented as + arguments:: + + .. automodule:: noodle + :members: + :private-members: _spicy, _garlickly + + .. versionadded:: 1.1 + .. versionchanged:: 3.2 + The option can now take arguments. + + .. rst:directive:option:: special-members + :type: no value or comma separated list + + If set, autodoc will also generate document for the special members + (that is, those named like ``__special__``):: + + .. autoclass:: my.Class + :members: + :special-members: + + It can also take an explicit list of member names to be documented as + arguments:: + + .. autoclass:: my.Class + :members: + :special-members: __init__, __name__ + + .. versionadded:: 1.1 + + .. versionchanged:: 1.2 + The option can now take arguments + + **Options and advanced usage** + * If you want to make the ``members`` option (or other options described below) the default, see :confval:`autodoc_default_options`. @@ -139,31 +202,6 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, .. versionchanged:: 3.5 The default options can be overridden or extended temporarily. - * Members without docstrings will be left out, unless you give the - ``undoc-members`` flag option:: - - .. automodule:: noodle - :members: - :undoc-members: - - * "Private" members (that is, those named like ``_private`` or ``__private``) - will be included if the ``private-members`` flag option is given:: - - .. automodule:: noodle - :members: - :private-members: - - It can also take an explicit list of member names to be documented as - arguments:: - - .. automodule:: noodle - :members: - :private-members: _spicy, _garlickly - - .. versionadded:: 1.1 - .. versionchanged:: 3.2 - The option can now take arguments. - * autodoc considers a member private if its docstring contains ``:meta private:`` in its :ref:`info-field-lists`. For example: @@ -203,21 +241,6 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, .. versionadded:: 3.5 - * Python "special" members (that is, those named like ``__special__``) will - be included if the ``special-members`` flag option is given:: - - .. autoclass:: my.Class - :members: - :private-members: - :special-members: - - would document both "private" and "special" members of the class. - - .. versionadded:: 1.1 - - .. versionchanged:: 1.2 - The option can now take arguments, i.e. the special members to document. - * For classes and exceptions, members inherited from base classes will be left out when documenting all members, unless you give the ``inherited-members`` option, in addition to ``members``:: @@ -586,6 +609,16 @@ There are also config values that you can set: .. __: https://mypy.readthedocs.io/en/latest/kinds_of_types.html#type-aliases .. versionadded:: 3.3 +.. confval:: autodoc_preserve_defaults + + If True, the default argument values of functions will be not evaluated on + generating document. It preserves them as is in the source code. + + .. versionadded:: 4.0 + + Added as an experimental feature. This will be integrated into autodoc core + in the future. + .. confval:: autodoc_warningiserror This value controls the behavior of :option:`sphinx-build -W` during diff --git a/doc/usage/extensions/autosummary.rst b/doc/usage/extensions/autosummary.rst index 03ea7548e..28f207de7 100644 --- a/doc/usage/extensions/autosummary.rst +++ b/doc/usage/extensions/autosummary.rst @@ -19,11 +19,13 @@ The :mod:`sphinx.ext.autosummary` extension does this in two parts: that contain links to the documented items, and short summary blurbs extracted from their docstrings. -2. Optionally, the convenience script :program:`sphinx-autogen` or the new - :confval:`autosummary_generate` config value can be used to generate short - "stub" files for the entries listed in the :rst:dir:`autosummary` directives. - These files by default contain only the corresponding - :mod:`sphinx.ext.autodoc` directive, but can be customized with templates. +2. A :rst:dir:`autosummary` directive also generates short "stub" files for the + entries listed in its content. These files by default contain only the + corresponding :mod:`sphinx.ext.autodoc` directive, but can be customized with + templates. + + The :program:`sphinx-autogen` script is also able to generate "stub" files + from command line. .. rst:directive:: autosummary @@ -161,7 +163,7 @@ also use these config values: .. confval:: autosummary_generate Boolean indicating whether to scan all found documents for autosummary - directives, and to generate stub pages for each. It is disabled by default. + directives, and to generate stub pages for each. It is enabled by default. Can also be a list of documents for which stub pages should be generated. @@ -173,6 +175,10 @@ also use these config values: Emits :event:`autodoc-skip-member` event as :mod:`~sphinx.ext.autodoc` does. + .. versionchanged:: 4.0 + + Enabled by default. + .. confval:: autosummary_generate_overwrite If true, autosummary overwrites existing files by generated stub pages. diff --git a/doc/usage/installation.rst b/doc/usage/installation.rst index 0ea54b220..f0384ea9d 100644 --- a/doc/usage/installation.rst +++ b/doc/usage/installation.rst @@ -107,7 +107,30 @@ Anaconda Windows ------- -.. todo:: Could we start packaging this? +Sphinx can be install using `Chocolatey`__ or +:ref:`installed manually `. + +__ https://chocolatey.org/ + +Chocolatey +~~~~~~~~~~ + +:: + + $ choco install sphinx + +You would need to `install Chocolatey +`_ +before running this. + +For more information, refer to the `chocolatey page`__. + +__ https://chocolatey.org/packages/sphinx/ + +.. _windows-other-method: + +Other Methods +~~~~~~~~~~~~~ Most Windows users do not have Python installed by default, so we begin with the installation of Python itself. To check if you already have Python diff --git a/doc/usage/restructuredtext/directives.rst b/doc/usage/restructuredtext/directives.rst index 53625ac9e..995804e37 100644 --- a/doc/usage/restructuredtext/directives.rst +++ b/doc/usage/restructuredtext/directives.rst @@ -197,9 +197,9 @@ tables of contents. The ``toctree`` directive is the central element. ` to let a document be built, but notify Sphinx that it is not reachable via a toctree. - The "master document" (selected by :confval:`master_doc`) is the "root" of - the TOC tree hierarchy. It can be used as the documentation's main page, or - as a "full table of contents" if you don't give a ``maxdepth`` option. + The "root document" (selected by :confval:`root_doc`) is the "root" of the TOC + tree hierarchy. It can be used as the documentation's main page, or as a + "full table of contents" if you don't give a ``maxdepth`` option. .. versionchanged:: 0.3 Added "globbing" option. diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 9bcfaaabf..9ec4898c1 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -338,6 +338,54 @@ class pending_xref(nodes.Inline, nodes.Element): """ +class pending_xref_condition(nodes.Inline, nodes.TextElement): + """Node for cross-references that are used to choose appropriate + content of the reference by conditions on the resolving phase. + + When the :py:class:`pending_xref` node contains one or more + **pending_xref_condition** nodes, the cross-reference resolver + should choose the content of the reference using defined conditions + in ``condition`` attribute of each pending_xref_condition nodes:: + + + + StringIO + + + io.StringIO + + After the processing of cross-reference resolver, one of the content node + under pending_xref_condition node is chosen by its condition and to be + removed all of pending_xref_condition nodes:: + + # When resolved the cross-reference successfully + + + StringIO + + # When resolution is failed + + + io.StringIO + + .. note:: This node is only allowed to be placed under pending_xref node. + It is not allows to place it under other nodes. In addition, + pending_xref node must contain only pending_xref_condition + nodes if it contains one or more pending_xref_condition nodes. + + The pending_xref_condition node should have **condition** attribute. + Domains can be store their individual conditions into the attribute to + filter contents on resolving phase. As a reserved condition name, + ``condition="*"`` is used for the fallback of resolution failure. + Additionally, as a recommended condition name, ``condition="resolved"`` + is used for the representation of resolstion success in the intersphinx + module. + + .. versionadded:: 4.0 + """ + + class number_reference(nodes.reference): """Node for number references, similar to pending_xref.""" diff --git a/sphinx/application.py b/sphinx/application.py index b5cc44268..7812cecc9 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -1102,7 +1102,7 @@ class Sphinx: If *override* is True, the given *cls* is forcedly installed even if a documenter having the same name is already installed. - .. todo:: Add real docs for Documenter and subclassing + See :ref:`autodoc_ext_tutorial`. .. versionadded:: 0.6 .. versionchanged:: 2.2 diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 7e361652f..c4ac432e4 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -413,9 +413,9 @@ class Builder: else: self._read_serial(docnames) - if self.config.master_doc not in self.env.all_docs: - raise SphinxError('master file %s not found' % - self.env.doc2path(self.config.master_doc)) + if self.config.root_doc not in self.env.all_docs: + raise SphinxError('root file %s not found' % + self.env.doc2path(self.config.root_doc)) for retval in self.events.emit('env-updated', self.env): if retval is not None: @@ -517,7 +517,7 @@ class Builder: for tocdocname in self.env.files_to_rebuild.get(docname, set()): if tocdocname in self.env.found_docs: docnames.add(tocdocname) - docnames.add(self.config.master_doc) + docnames.add(self.config.root_doc) with progress_message(__('preparing documents')): self.prepare_writing(docnames) diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index 453474e09..3b19bb8d0 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -222,14 +222,14 @@ class EpubBuilder(StandaloneHTMLBuilder): appeared.add(node['refuri']) def get_toc(self) -> None: - """Get the total table of contents, containing the master_doc + """Get the total table of contents, containing the root_doc and pre and post files not managed by sphinx. """ - doctree = self.env.get_and_resolve_doctree(self.config.master_doc, + doctree = self.env.get_and_resolve_doctree(self.config.root_doc, self, prune_toctrees=False, includehidden=True) self.refnodes = self.get_refnodes(doctree, []) - master_dir = path.dirname(self.config.master_doc) + master_dir = path.dirname(self.config.root_doc) if master_dir: master_dir += '/' # XXX or os.sep? for item in self.refnodes: @@ -237,13 +237,13 @@ class EpubBuilder(StandaloneHTMLBuilder): self.toc_add_files(self.refnodes) def toc_add_files(self, refnodes: List[Dict[str, Any]]) -> None: - """Add the master_doc, pre and post files to a list of refnodes. + """Add the root_doc, pre and post files to a list of refnodes. """ refnodes.insert(0, { 'level': 1, - 'refuri': html.escape(self.config.master_doc + self.out_suffix), + 'refuri': html.escape(self.config.root_doc + self.out_suffix), 'text': ssp(html.escape( - self.env.titles[self.config.master_doc].astext())) + self.env.titles[self.config.root_doc].astext())) }) for file, text in reversed(self.config.epub_pre_files): refnodes.insert(0, { @@ -677,7 +677,7 @@ class EpubBuilder(StandaloneHTMLBuilder): logger.info(__('writing toc.ncx file...')) if self.config.epub_tocscope == 'default': - doctree = self.env.get_and_resolve_doctree(self.config.master_doc, + doctree = self.env.get_and_resolve_doctree(self.config.root_doc, self, prune_toctrees=False, includehidden=False) refnodes = self.get_refnodes(doctree, []) diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index 8a0dab303..623ee45a4 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -166,7 +166,7 @@ class Epub3Builder(_epub_base.EpubBuilder): if self.config.epub_tocscope == 'default': doctree = self.env.get_and_resolve_doctree( - self.config.master_doc, self, + self.config.root_doc, self, prune_toctrees=False, includehidden=False) refnodes = self.get_refnodes(doctree, []) self.toc_add_files(refnodes) diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py index a68594a6d..115f73538 100644 --- a/sphinx/builders/html/__init__.py +++ b/sphinx/builders/html/__init__.py @@ -494,7 +494,8 @@ class StandaloneHTMLBuilder(Builder): 'version': self.config.version, 'last_updated': self.last_updated, 'copyright': self.config.copyright, - 'master_doc': self.config.master_doc, + 'master_doc': self.config.root_doc, + 'root_doc': self.config.root_doc, 'use_opensearch': self.config.html_use_opensearch, 'docstitle': self.config.html_title, 'shorttitle': self.config.html_short_title, @@ -1247,18 +1248,31 @@ def validate_html_favicon(app: Sphinx, config: Config) -> None: config.html_favicon = None # type: ignore +class _stable_repr_object(): + + def __repr__(self): + return '' + + +UNSET = _stable_repr_object() + + def migrate_html_add_permalinks(app: Sphinx, config: Config) -> None: """Migrate html_add_permalinks to html_permalinks*.""" - if config.html_add_permalinks: - # RemovedInSphinx60Warning - logger.warning(__('html_add_permalinks has been deprecated since v3.5.0. ' - 'Please use html_permalinks and html_permalinks_icon instead.')) - if (isinstance(config.html_add_permalinks, bool) and - config.html_add_permalinks is False): - config.html_permalinks = False # type: ignore - else: - config.html_permalinks_icon = html.escape(config.html_add_permalinks) # type: ignore # NOQA + html_add_permalinks = config.html_add_permalinks + if html_add_permalinks is UNSET: + return + # RemovedInSphinx60Warning + logger.warning(__('html_add_permalinks has been deprecated since v3.5.0. ' + 'Please use html_permalinks and html_permalinks_icon instead.')) + if not html_add_permalinks: + config.html_permalinks = False # type: ignore[attr-defined] + return + + config.html_permalinks_icon = html.escape( # type: ignore[attr-defined] + html_add_permalinks + ) # for compatibility import sphinxcontrib.serializinghtml # NOQA @@ -1290,7 +1304,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('html_sidebars', {}, 'html') app.add_config_value('html_additional_pages', {}, 'html') app.add_config_value('html_domain_indices', True, 'html', [list]) - app.add_config_value('html_add_permalinks', None, 'html') + app.add_config_value('html_add_permalinks', UNSET, 'html') app.add_config_value('html_permalinks', True, 'html') app.add_config_value('html_permalinks_icon', '¶', 'html') app.add_config_value('html_use_index', True, 'html') diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index dc533b486..681d3cfe6 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -517,7 +517,7 @@ def default_latex_documents(config: Config) -> List[Tuple[str, str, str, str, st """ Better default latex_documents settings. """ project = texescape.escape(config.project, config.latex_engine) author = texescape.escape(config.author, config.latex_engine) - return [(config.master_doc, + return [(config.root_doc, make_filename_from_project(config.project) + '.tex', texescape.escape_abbr(project), texescape.escape_abbr(author), diff --git a/sphinx/builders/latex/transforms.py b/sphinx/builders/latex/transforms.py index e16f925a1..0a74eded4 100644 --- a/sphinx/builders/latex/transforms.py +++ b/sphinx/builders/latex/transforms.py @@ -42,7 +42,7 @@ class SubstitutionDefinitionsRemover(SphinxPostTransform): # should be invoked after Substitutions process default_priority = Substitutions.default_priority + 1 - builders = ('latex',) + formats = ('latex',) def run(self, **kwargs: Any) -> None: for node in self.document.traverse(nodes.substitution_definition): @@ -57,7 +57,7 @@ class ShowUrlsTransform(SphinxPostTransform): .. note:: This transform is used for integrated doctree """ default_priority = 400 - builders = ('latex',) + formats = ('latex',) # references are expanded to footnotes (or not) expanded = False @@ -345,7 +345,7 @@ class LaTeXFootnoteTransform(SphinxPostTransform): """ default_priority = 600 - builders = ('latex',) + formats = ('latex',) def run(self, **kwargs: Any) -> None: footnotes = list(self.document.traverse(nodes.footnote)) @@ -497,7 +497,7 @@ class BibliographyTransform(SphinxPostTransform): ... """ default_priority = 750 - builders = ('latex',) + formats = ('latex',) def run(self, **kwargs: Any) -> None: citations = thebibliography() @@ -516,7 +516,7 @@ class CitationReferenceTransform(SphinxPostTransform): pending_xref nodes to citation_reference. """ default_priority = 5 # before ReferencesResolver - builders = ('latex',) + formats = ('latex',) def run(self, **kwargs: Any) -> None: domain = cast(CitationDomain, self.env.get_domain('citation')) @@ -536,7 +536,7 @@ class MathReferenceTransform(SphinxPostTransform): nodes to math_reference. """ default_priority = 5 # before ReferencesResolver - builders = ('latex',) + formats = ('latex',) def run(self, **kwargs: Any) -> None: equations = self.env.get_domain('math').data['objects'] @@ -551,7 +551,7 @@ class MathReferenceTransform(SphinxPostTransform): class LiteralBlockTransform(SphinxPostTransform): """Replace container nodes for literal_block by captioned_literal_block.""" default_priority = 400 - builders = ('latex',) + formats = ('latex',) def run(self, **kwargs: Any) -> None: matcher = NodeMatcher(nodes.container, literal_block=True) @@ -563,7 +563,7 @@ class LiteralBlockTransform(SphinxPostTransform): class DocumentTargetTransform(SphinxPostTransform): """Add :doc label to the first section of each document.""" default_priority = 400 - builders = ('latex',) + formats = ('latex',) def run(self, **kwargs: Any) -> None: for node in self.document.traverse(addnodes.start_of_file): @@ -599,7 +599,7 @@ class IndexInSectionTitleTransform(SphinxPostTransform): ... """ default_priority = 400 - builders = ('latex',) + formats = ('latex',) def run(self, **kwargs: Any) -> None: for node in self.document.traverse(nodes.title): diff --git a/sphinx/builders/manpage.py b/sphinx/builders/manpage.py index e1e1b77f0..f994309e1 100644 --- a/sphinx/builders/manpage.py +++ b/sphinx/builders/manpage.py @@ -109,7 +109,7 @@ class ManualPageBuilder(Builder): def default_man_pages(config: Config) -> List[Tuple[str, str, str, List[str], int]]: """ Better default man_pages settings. """ filename = make_filename_from_project(config.project) - return [(config.master_doc, filename, '%s %s' % (config.project, config.release), + return [(config.root_doc, filename, '%s %s' % (config.project, config.release), [config.author], 1)] diff --git a/sphinx/builders/singlehtml.py b/sphinx/builders/singlehtml.py index 2e72887e3..1ef618dd0 100644 --- a/sphinx/builders/singlehtml.py +++ b/sphinx/builders/singlehtml.py @@ -42,7 +42,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): def get_target_uri(self, docname: str, typ: str = None) -> str: if docname in self.env.all_docs: # all references are on the same page... - return self.config.master_doc + self.out_suffix + \ + return self.config.root_doc + self.out_suffix + \ '#document-' + docname else: # chances are this is a html_additional_page @@ -54,7 +54,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): def fix_refuris(self, tree: Node) -> None: # fix refuris with double anchor - fname = self.config.master_doc + self.out_suffix + fname = self.config.root_doc + self.out_suffix for refnode in tree.traverse(nodes.reference): if 'refuri' not in refnode: continue @@ -75,7 +75,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): return self.render_partial(toctree)['fragment'] def assemble_doctree(self) -> nodes.document: - master = self.config.master_doc + master = self.config.root_doc tree = self.env.get_doctree(master) tree = inline_all_toctrees(self, set(), master, tree, darkgreen, [master]) tree['docname'] = master @@ -99,7 +99,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): alias = "%s/%s" % (docname, id) new_secnumbers[alias] = secnum - return {self.config.master_doc: new_secnumbers} + return {self.config.root_doc: new_secnumbers} def assemble_toc_fignumbers(self) -> Dict[str, Dict[str, Dict[str, Tuple[int, ...]]]]: # Assemble toc_fignumbers to resolve figure numbers on SingleHTML. @@ -120,11 +120,11 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): for id, fignum in fignums.items(): new_fignumbers[alias][id] = fignum - return {self.config.master_doc: new_fignumbers} + return {self.config.root_doc: new_fignumbers} def get_doc_context(self, docname: str, body: str, metatags: str) -> Dict: # no relation links... - toctree = TocTree(self.env).get_toctree_for(self.config.master_doc, self, False) + toctree = TocTree(self.env).get_toctree_for(self.config.root_doc, self, False) # if there is no toctree, toc is None if toctree: self.fix_refuris(toctree) @@ -160,8 +160,8 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): self.env.toc_fignumbers = self.assemble_toc_fignumbers() with progress_message(__('writing')): - self.write_doc_serialized(self.config.master_doc, doctree) - self.write_doc(self.config.master_doc, doctree) + self.write_doc_serialized(self.config.root_doc, doctree) + self.write_doc(self.config.root_doc, doctree) def finish(self) -> None: self.write_additional_files() diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py index 1a56be0f9..bb2039e61 100644 --- a/sphinx/builders/texinfo.py +++ b/sphinx/builders/texinfo.py @@ -197,7 +197,7 @@ class TexinfoBuilder(Builder): def default_texinfo_documents(config: Config) -> List[Tuple[str, str, str, str, str, str, str]]: # NOQA """ Better default texinfo_documents settings. """ filename = make_filename_from_project(config.project) - return [(config.master_doc, filename, config.project, config.author, filename, + return [(config.root_doc, filename, config.project, config.author, filename, 'One line description of project', 'Miscellaneous')] diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 4ef9335a4..a40a21073 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -162,10 +162,22 @@ class QuickstartRenderer(SphinxRenderer): self.templatedir = templatedir or '' super().__init__() + def _has_custom_template(self, template_name: str) -> bool: + """Check if custom template file exists. + + Note: Please don't use this function from extensions. + It will be removed in the future without deprecation period. + """ + template = path.join(self.templatedir, path.basename(template_name)) + if self.templatedir and path.exists(template): + return True + else: + return False + def render(self, template_name: str, context: Dict) -> str: - user_template = path.join(self.templatedir, path.basename(template_name)) - if self.templatedir and path.exists(user_template): - return self.render_from_file(user_template, context) + if self._has_custom_template(template_name): + custom_template = path.join(self.templatedir, path.basename(template_name)) + return self.render_from_file(custom_template, context) else: return super().render(template_name, context) @@ -318,6 +330,7 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir: if 'mastertocmaxdepth' not in d: d['mastertocmaxdepth'] = 2 + d['root_doc'] = d['master'] d['now'] = time.asctime() d['project_underline'] = column_width(d['project']) * '=' d.setdefault('extensions', []) @@ -362,7 +375,13 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir: write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d)) masterfile = path.join(srcdir, d['master'] + d['suffix']) - write_file(masterfile, template.render('quickstart/master_doc.rst_t', d)) + if template._has_custom_template('quickstart/master_doc.rst_t'): + msg = ('A custom template `master_doc.rst_t` found. It has been renamed to ' + '`root_doc.rst_t`. Please rename it on your project too.') + print(colorize('red', msg)) # RemovedInSphinx60Warning + write_file(masterfile, template.render('quickstart/master_doc.rst_t', d)) + else: + write_file(masterfile, template.render('quickstart/root_doc.rst_t', d)) if d.get('make_mode') is True: makefile_template = 'quickstart/Makefile.new_t' diff --git a/sphinx/config.py b/sphinx/config.py index 735a3e0b3..d7f9c4f8a 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -105,6 +105,7 @@ class Config: 'figure_language_filename': ('{root}.{language}{ext}', 'env', [str]), 'master_doc': ('index', 'env', []), + 'root_doc': (lambda config: config.master_doc, 'env', []), 'source_suffix': ({'.rst': 'restructuredtext'}, 'env', Any), 'source_encoding': ('utf-8-sig', 'env', []), 'exclude_patterns': ([], 'env', []), @@ -461,17 +462,17 @@ def check_primary_domain(app: "Sphinx", config: Config) -> None: config.primary_domain = None # type: ignore -def check_master_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str], - changed: Set[str], removed: Set[str]) -> Set[str]: - """Adjust master_doc to 'contents' to support an old project which does not have - no master_doc setting. +def check_root_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str], + changed: Set[str], removed: Set[str]) -> Set[str]: + """Adjust root_doc to 'contents' to support an old project which does not have + no root_doc setting. """ - if (app.config.master_doc == 'index' and + if (app.config.root_doc == 'index' and 'index' not in app.project.docnames and 'contents' in app.project.docnames): - logger.warning(__('Since v2.0, Sphinx uses "index" as master_doc by default. ' - 'Please add "master_doc = \'contents\'" to your conf.py.')) - app.config.master_doc = "contents" # type: ignore + logger.warning(__('Since v2.0, Sphinx uses "index" as root_doc by default. ' + 'Please add "root_doc = \'contents\'" to your conf.py.')) + app.config.root_doc = "contents" # type: ignore return changed @@ -483,7 +484,7 @@ def setup(app: "Sphinx") -> Dict[str, Any]: app.connect('config-inited', correct_copyright_year, priority=800) app.connect('config-inited', check_confval_types, priority=800) app.connect('config-inited', check_primary_domain, priority=800) - app.connect('env-get-outdated', check_master_doc) + app.connect('env-get-outdated', check_root_doc) return { 'version': 'builtin', diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py index 5baa0994c..1c3cfd853 100644 --- a/sphinx/directives/patches.py +++ b/sphinx/directives/patches.py @@ -6,7 +6,9 @@ :license: BSD, see LICENSE for details. """ +import os import warnings +from os import path from typing import TYPE_CHECKING, Any, Dict, List, Tuple, cast from docutils import nodes @@ -18,13 +20,19 @@ from sphinx import addnodes from sphinx.deprecation import RemovedInSphinx60Warning from sphinx.directives import optional_int from sphinx.domains.math import MathDomain +from sphinx.locale import __ +from sphinx.util import logging from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import set_source_info +from sphinx.util.osutil import SEP, os_path, relpath if TYPE_CHECKING: from sphinx.application import Sphinx +logger = logging.getLogger(__name__) + + class Figure(images.Figure): """The figure directive which applies `:name:` option to the figure node instead of the image node. @@ -87,22 +95,26 @@ class RSTTable(tables.RSTTable): class CSVTable(tables.CSVTable): - """The csv-table directive which sets source and line information to its caption. - - Only for docutils-0.13 or older version.""" + """The csv-table directive which searches a CSV file from Sphinx project's source + directory when an absolute path is given via :file: option. + """ def run(self) -> List[Node]: - warnings.warn('RSTTable is deprecated.', - RemovedInSphinx60Warning) + if 'file' in self.options and self.options['file'].startswith((SEP, os.sep)): + env = self.state.document.settings.env + filename = self.options['file'] + if path.exists(filename): + logger.warning(__('":file:" option for csv-table directive now recognizes ' + 'an absolute path as a relative path from source directory. ' + 'Please update your document.'), + location=(env.docname, self.lineno)) + else: + abspath = path.join(env.srcdir, os_path(self.options['file'][1:])) + docdir = path.dirname(env.doc2path(env.docname)) + self.options['file'] = relpath(abspath, docdir) + return super().run() - def make_title(self) -> Tuple[nodes.title, List[system_message]]: - title, message = super().make_title() - if title: - set_source_info(self, title) - - return title, message - class ListTable(tables.ListTable): """The list-table directive which sets source and line information to its caption. @@ -110,7 +122,7 @@ class ListTable(tables.ListTable): Only for docutils-0.13 or older version.""" def run(self) -> List[Node]: - warnings.warn('RSTTable is deprecated.', + warnings.warn('ListTable is deprecated.', RemovedInSphinx60Warning) return super().run() @@ -224,6 +236,7 @@ class MathDirective(SphinxDirective): def setup(app: "Sphinx") -> Dict[str, Any]: directives.register_directive('figure', Figure) directives.register_directive('meta', Meta) + directives.register_directive('csv-table', CSVTable) directives.register_directive('code', Code) directives.register_directive('math', MathDirective) diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 061010d66..0fecbad6d 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -387,19 +387,6 @@ class ASTPostfixDec(ASTPostfixOp): signode.append(nodes.Text('--')) -class ASTPostfixMember(ASTPostfixOp): - def __init__(self, name): - self.name = name - - def _stringify(self, transform: StringifyTransform) -> str: - return '.' + transform(self.name) - - def describe_signature(self, signode: TextElement, mode: str, - env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('.')) - self.name.describe_signature(signode, 'noneIsName', env, symbol) - - class ASTPostfixMemberOfPointer(ASTPostfixOp): def __init__(self, name): self.name = name @@ -682,15 +669,24 @@ class ASTParameters(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - paramlist = addnodes.desc_parameterlist() - for arg in self.args: - param = addnodes.desc_parameter('', '', noemph=True) - if mode == 'lastIsName': # i.e., outer-function params + # only use the desc_parameterlist for the outer list, not for inner lists + if mode == 'lastIsName': + paramlist = addnodes.desc_parameterlist() + for arg in self.args: + param = addnodes.desc_parameter('', '', noemph=True) arg.describe_signature(param, 'param', env, symbol=symbol) - else: - arg.describe_signature(param, 'markType', env, symbol=symbol) - paramlist += param - signode += paramlist + paramlist += param + signode += paramlist + else: + signode += nodes.Text('(', '(') + first = True + for arg in self.args: + if not first: + signode += nodes.Text(', ', ', ') + first = False + arg.describe_signature(signode, 'markType', env, symbol=symbol) + signode += nodes.Text(')', ')') + for attr in self.attrs: signode += nodes.Text(' ') attr.describe_signature(signode) @@ -2256,7 +2252,7 @@ class DefinitionParser(BaseParser): # | postfix "[" expression "]" # | postfix "[" braced-init-list [opt] "]" # | postfix "(" expression-list [opt] ")" - # | postfix "." id-expression + # | postfix "." id-expression // taken care of in primary by nested name # | postfix "->" id-expression # | postfix "++" # | postfix "--" @@ -2274,17 +2270,6 @@ class DefinitionParser(BaseParser): self.fail("Expected ']' in end of postfix expression.") postFixes.append(ASTPostfixArray(expr)) continue - if self.skip_string('.'): - if self.skip_string('*'): - # don't steal the dot - self.pos -= 2 - elif self.skip_string('..'): - # don't steal the dot - self.pos -= 3 - else: - name = self._parse_nested_name() - postFixes.append(ASTPostfixMember(name)) - continue if self.skip_string('->'): if self.skip_string('*'): # don't steal the arrow @@ -2693,16 +2678,13 @@ class DefinitionParser(BaseParser): def _parse_declarator_name_suffix( self, named: Union[bool, str], paramMode: str, typed: bool ) -> ASTDeclarator: + assert named in (True, False, 'single') # now we should parse the name, and then suffixes - if named == 'maybe': - pos = self.pos - try: - declId = self._parse_nested_name() - except DefinitionError: - self.pos = pos - declId = None - elif named == 'single': + if named == 'single': if self.match(identifier_re): + if self.matched_text in _keywords: + self.fail("Expected identifier, " + "got keyword: %s" % self.matched_text) identifier = ASTIdentifier(self.matched_text) declId = ASTNestedName([identifier], rooted=False) else: @@ -2880,8 +2862,8 @@ class DefinitionParser(BaseParser): def _parse_type(self, named: Union[bool, str], outer: str = None) -> ASTType: """ - named=False|'maybe'|True: 'maybe' is e.g., for function objects which - doesn't need to name the arguments + named=False|'single'|True: 'single' is e.g., for function objects which + doesn't need to name the arguments, but otherwise is a single name """ if outer: # always named if outer not in ('type', 'member', 'function'): diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 7ee023d1d..3bd764de5 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -306,6 +306,7 @@ _operator_re = re.compile(r'''(?x) | \+\+ | -- | ->\*? | \, | (<<|>>)=? | && | \|\| + | <=> | [!<>=/*%+|&^~-]=? | (\b(and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|xor|xor_eq)\b) ''') @@ -494,6 +495,7 @@ _id_operator_v2 = { '>': 'gt', '<=': 'le', '>=': 'ge', + '<=>': 'ss', '!': 'nt', 'not': 'nt', '&&': 'aa', 'and': 'aa', '||': 'oo', 'or': 'oo', @@ -528,7 +530,7 @@ _expression_bin_ops = [ ['^', 'xor'], ['&', 'bitand'], ['==', '!=', 'not_eq'], - ['<=', '>=', '<', '>'], + ['<=>', '<=', '>=', '<', '>'], ['<<', '>>'], ['+', '-'], ['*', '/', '%'], @@ -1965,15 +1967,23 @@ class ASTParametersQualifiers(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - paramlist = addnodes.desc_parameterlist() - for arg in self.args: - param = addnodes.desc_parameter('', '', noemph=True) - if mode == 'lastIsName': # i.e., outer-function params + # only use the desc_parameterlist for the outer list, not for inner lists + if mode == 'lastIsName': + paramlist = addnodes.desc_parameterlist() + for arg in self.args: + param = addnodes.desc_parameter('', '', noemph=True) arg.describe_signature(param, 'param', env, symbol=symbol) - else: - arg.describe_signature(param, 'markType', env, symbol=symbol) - paramlist += param - signode += paramlist + paramlist += param + signode += paramlist + else: + signode += nodes.Text('(', '(') + first = True + for arg in self.args: + if not first: + signode += nodes.Text(', ', ', ') + first = False + arg.describe_signature(signode, 'markType', env, symbol=symbol) + signode += nodes.Text(')', ')') def _add_anno(signode: TextElement, text: str) -> None: signode += nodes.Text(' ') @@ -5309,7 +5319,7 @@ class DefinitionParser(BaseParser): # exclusive-or = and ^ # and = equality & # equality = relational ==, != - # relational = shift <, >, <=, >= + # relational = shift <, >, <=, >=, <=> # shift = additive <<, >> # additive = multiplicative +, - # multiplicative = pm *, /, % @@ -7644,10 +7654,11 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value("cpp_debug_lookup", False, '') app.add_config_value("cpp_debug_show_tree", False, '') - def setDebugFlags(app): + def initStuff(app): Symbol.debug_lookup = app.config.cpp_debug_lookup Symbol.debug_show_tree = app.config.cpp_debug_show_tree - app.connect("builder-inited", setDebugFlags) + app.config.cpp_index_common_prefix.sort(reverse=True) + app.connect("builder-inited", initStuff) return { 'version': 'builtin', diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 5e430a1d7..40a67f82c 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -22,7 +22,7 @@ from docutils.nodes import Element, Node from docutils.parsers.rst import directives from sphinx import addnodes -from sphinx.addnodes import desc_signature, pending_xref +from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.deprecation import RemovedInSphinx50Warning @@ -37,7 +37,7 @@ from sphinx.util import logging from sphinx.util.docfields import Field, GroupedField, TypedField from sphinx.util.docutils import SphinxDirective from sphinx.util.inspect import signature_from_str -from sphinx.util.nodes import make_id, make_refnode +from sphinx.util.nodes import find_pending_xref_condition, make_id, make_refnode from sphinx.util.typing import TextlikeNode logger = logging.getLogger(__name__) @@ -92,7 +92,17 @@ def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xr else: kwargs = {} - return pending_xref('', nodes.Text(text), + if env.config.python_use_unqualified_type_names: + # Note: It would be better to use qualname to describe the object to support support + # nested classes. But python domain can't access the real python object because this + # module should work not-dynamically. + shortname = text.split('.')[-1] + contnodes = [pending_xref_condition('', shortname, condition='resolved'), + pending_xref_condition('', text, condition='*')] # type: List[Node] + else: + contnodes = [nodes.Text(text)] + + return pending_xref('', *contnodes, refdomain='py', reftype=reftype, reftarget=text, **kwargs) @@ -1209,7 +1219,15 @@ class PythonDomain(Domain): if obj[2] == 'module': return self._make_module_refnode(builder, fromdocname, name, contnode) else: - return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name) + # determine the content of the reference by conditions + content = find_pending_xref_condition(node, 'resolved') + if content: + children = content.children + else: + # if not found, use contnode + children = [contnode] + + return make_refnode(builder, fromdocname, obj[0], obj[1], children, name) def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, target: str, node: pending_xref, contnode: Element @@ -1226,9 +1244,17 @@ class PythonDomain(Domain): self._make_module_refnode(builder, fromdocname, name, contnode))) else: + # determine the content of the reference by conditions + content = find_pending_xref_condition(node, 'resolved') + if content: + children = content.children + else: + # if not found, use contnode + children = [contnode] + results.append(('py:' + self.role_for_objtype(obj[2]), make_refnode(builder, fromdocname, obj[0], obj[1], - contnode, name))) + children, name))) return results def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str, @@ -1295,6 +1321,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.setup_extension('sphinx.directives') app.add_domain(PythonDomain) + app.add_config_value('python_use_unqualified_type_names', False, 'env') app.connect('object-description-transform', filter_meta_fields) app.connect('missing-reference', builtin_resolver, priority=900) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 28599c977..60ede8188 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -600,7 +600,7 @@ class BuildEnvironment: traversed.add(subdocname) relations = {} - docnames = traverse_toctree(None, self.config.master_doc) + docnames = traverse_toctree(None, self.config.root_doc) prevdoc = None parent, docname = next(docnames) for nextparent, nextdoc in docnames: @@ -618,7 +618,7 @@ class BuildEnvironment: included = set().union(*self.included.values()) # type: ignore for docname in sorted(self.all_docs): if docname not in self.files_to_rebuild: - if docname == self.config.master_doc: + if docname == self.config.root_doc: # the master file is not included anywhere ;) continue if docname in included: diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py index 2e33cf702..d12055b84 100644 --- a/sphinx/environment/adapters/toctree.py +++ b/sphinx/environment/adapters/toctree.py @@ -315,7 +315,7 @@ class TocTree: def get_toctree_for(self, docname: str, builder: "Builder", collapse: bool, **kwargs: Any) -> Element: """Return the global TOC nodetree.""" - doctree = self.env.get_doctree(self.env.config.master_doc) + doctree = self.env.get_doctree(self.env.config.root_doc) toctrees = [] # type: List[Element] if 'includehidden' not in kwargs: kwargs['includehidden'] = True diff --git a/sphinx/environment/collectors/title.py b/sphinx/environment/collectors/title.py index 5225155e8..28e967427 100644 --- a/sphinx/environment/collectors/title.py +++ b/sphinx/environment/collectors/title.py @@ -50,7 +50,7 @@ class TitleCollector(EnvironmentCollector): break else: # document has no title - titlenode += nodes.Text('') + titlenode += nodes.Text(doctree.get('title', '')) app.env.titles[app.env.docname] = titlenode app.env.longtitles[app.env.docname] = longtitlenode diff --git a/sphinx/environment/collectors/toctree.py b/sphinx/environment/collectors/toctree.py index da0b3fe6c..aeb6ef3a6 100644 --- a/sphinx/environment/collectors/toctree.py +++ b/sphinx/environment/collectors/toctree.py @@ -281,7 +281,7 @@ class TocTreeCollector(EnvironmentCollector): _walk_doctree(docname, doctree, secnum) if env.config.numfig: - _walk_doc(env.config.master_doc, tuple()) + _walk_doc(env.config.root_doc, tuple()) for docname, fignums in env.toc_fignumbers.items(): if fignums != old_fignumbers.get(docname): rewrite_needed.append(docname) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 2ac24ebff..0b5709301 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1812,6 +1812,8 @@ class TypeVarMixin(DataDocumenterMixinBase): attrs = [repr(self.object.__name__)] for constraint in self.object.__constraints__: attrs.append(stringify_typehint(constraint)) + if self.object.__bound__: + attrs.append(r"bound=\ " + restify(self.object.__bound__)) if self.object.__covariant__: attrs.append("covariant=True") if self.object.__contravariant__: @@ -2632,6 +2634,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.connect('config-inited', migrate_autodoc_member_order, priority=800) + app.setup_extension('sphinx.ext.autodoc.preserve_defaults') app.setup_extension('sphinx.ext.autodoc.type_comment') app.setup_extension('sphinx.ext.autodoc.typehints') diff --git a/sphinx/ext/autodoc/preserve_defaults.py b/sphinx/ext/autodoc/preserve_defaults.py new file mode 100644 index 000000000..3d859fe8e --- /dev/null +++ b/sphinx/ext/autodoc/preserve_defaults.py @@ -0,0 +1,88 @@ +""" + sphinx.ext.autodoc.preserve_defaults + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Preserve the default argument values of function signatures in source code + and keep them not evaluated for readability. + + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import ast +import inspect +from typing import Any, Dict + +from sphinx.application import Sphinx +from sphinx.locale import __ +from sphinx.pycode.ast import parse as ast_parse +from sphinx.pycode.ast import unparse as ast_unparse +from sphinx.util import logging + +logger = logging.getLogger(__name__) + + +class DefaultValue: + def __init__(self, name: str) -> None: + self.name = name + + def __repr__(self) -> str: + return self.name + + +def get_function_def(obj: Any) -> ast.FunctionDef: + """Get FunctionDef object from living object. + This tries to parse original code for living object and returns + AST node for given *obj*. + """ + try: + source = inspect.getsource(obj) + if source.startswith((' ', r'\t')): + # subject is placed inside class or block. To read its docstring, + # this adds if-block before the declaration. + module = ast_parse('if True:\n' + source) + return module.body[0].body[0] # type: ignore + else: + module = ast_parse(source) + return module.body[0] # type: ignore + except (OSError, TypeError): # failed to load source code + return None + + +def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None: + """Update defvalue info of *obj* using type_comments.""" + if not app.config.autodoc_preserve_defaults: + return + + try: + function = get_function_def(obj) + if function.args.defaults or function.args.kw_defaults: + sig = inspect.signature(obj) + defaults = list(function.args.defaults) + kw_defaults = list(function.args.kw_defaults) + parameters = list(sig.parameters.values()) + for i, param in enumerate(parameters): + if param.default is not param.empty: + if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD): + value = DefaultValue(ast_unparse(defaults.pop(0))) # type: ignore + parameters[i] = param.replace(default=value) + else: + value = DefaultValue(ast_unparse(kw_defaults.pop(0))) # type: ignore + parameters[i] = param.replace(default=value) + sig = sig.replace(parameters=parameters) + obj.__signature__ = sig + except (AttributeError, TypeError): + # failed to update signature (ex. built-in or extension types) + pass + except NotImplementedError as exc: # failed to ast.unparse() + logger.warning(__("Failed to parse a default argument value for %r: %s"), obj, exc) + + +def setup(app: Sphinx) -> Dict[str, Any]: + app.add_config_value('autodoc_preserve_defaults', False, True) + app.connect('autodoc-before-process-signature', update_defvalue) + + return { + 'version': '1.0', + 'parallel_read_safe': True + } diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 7dbaaf686..1a0fd2409 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -772,7 +772,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.connect('builder-inited', process_generate_options) app.add_config_value('autosummary_context', {}, True) app.add_config_value('autosummary_filename_map', {}, 'html') - app.add_config_value('autosummary_generate', [], True, [bool]) + app.add_config_value('autosummary_generate', True, True, [bool]) app.add_config_value('autosummary_generate_overwrite', True, False) app.add_config_value('autosummary_mock_imports', lambda config: config.autodoc_mock_imports, 'env') diff --git a/sphinx/ext/imgconverter.py b/sphinx/ext/imgconverter.py index b0d40b551..84fe6549c 100644 --- a/sphinx/ext/imgconverter.py +++ b/sphinx/ext/imgconverter.py @@ -37,10 +37,10 @@ class ImagemagickConverter(ImageConverter): logger.debug('Invoking %r ...', args) subprocess.run(args, stdout=PIPE, stderr=PIPE, check=True) return True - except OSError: + except OSError as exc: logger.warning(__('convert command %r cannot be run, ' - 'check the image_converter setting'), - self.config.image_converter) + 'check the image_converter setting: %s'), + self.config.image_converter, exc) return False except CalledProcessError as exc: logger.warning(__('convert exited with error:\n' diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 5569ad9de..a01bcc37a 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -33,10 +33,11 @@ from typing import IO, Any, Dict, List, Tuple from urllib.parse import urlsplit, urlunsplit from docutils import nodes -from docutils.nodes import Element, TextElement +from docutils.nodes import TextElement from docutils.utils import relative_path import sphinx +from sphinx.addnodes import pending_xref from sphinx.application import Sphinx from sphinx.builders.html import INVENTORY_FILENAME from sphinx.config import Config @@ -44,6 +45,7 @@ from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ from sphinx.util import logging, requests from sphinx.util.inventory import InventoryFile +from sphinx.util.nodes import find_pending_xref_condition from sphinx.util.typing import Inventory logger = logging.getLogger(__name__) @@ -257,8 +259,8 @@ def load_mappings(app: Sphinx) -> None: inventories.main_inventory.setdefault(type, {}).update(objects) -def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: TextElement - ) -> nodes.reference: +def missing_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref, + contnode: TextElement) -> nodes.reference: """Attempt to resolve a missing reference via intersphinx references.""" target = node['reftarget'] inventories = InventoryAdapter(env) @@ -284,6 +286,17 @@ def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnod if 'py:attribute' in objtypes: # Since Sphinx-2.1, properties are stored as py:method objtypes.append('py:method') + + # determine the contnode by pending_xref_condition + content = find_pending_xref_condition(node, 'resolved') + if content: + # resolved condition found. + contnodes = content.children + contnode = content.children[0] # type: ignore + else: + # not resolved. Use the given contnode + contnodes = [contnode] + to_try = [(inventories.main_inventory, target)] if domain: full_qualified_name = env.get_domain(domain).get_full_qualified_name(node) @@ -316,7 +329,7 @@ def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnod newnode = nodes.reference('', '', internal=False, refuri=uri, reftitle=reftitle) if node.get('refexplicit'): # use whatever title was given - newnode.append(contnode) + newnode.extend(contnodes) elif dispname == '-' or \ (domain == 'std' and node['reftype'] == 'keyword'): # use whatever title was given, but strip prefix @@ -325,7 +338,7 @@ def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnod newnode.append(contnode.__class__(title[len(in_set) + 1:], title[len(in_set) + 1:])) else: - newnode.append(contnode) + newnode.extend(contnodes) else: # else use the given display name (used for :ref:) newnode.append(contnode.__class__(dispname, dispname)) diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 6bedf2e1c..c98ff0c88 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -146,7 +146,14 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # type: ignore # now merge in the information from the subprocess - env._viewcode_modules.update(other._viewcode_modules) # type: ignore + for modname, entry in other._viewcode_modules.items(): # type: ignore + if modname not in env._viewcode_modules: # type: ignore + env._viewcode_modules[modname] = entry # type: ignore + else: + used = env._viewcode_modules[modname][2] # type: ignore + for fullname, docname in entry[2].items(): + if fullname not in used: + used[fullname] = docname def env_purge_doc(app: Sphinx, env: BuildEnvironment, docname: str) -> None: diff --git a/sphinx/io.py b/sphinx/io.py index 96f181184..f6ab0e1ef 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -178,27 +178,12 @@ def read_doc(app: "Sphinx", env: BuildEnvironment, filename: str) -> nodes.docum # CommonMarkParser. parser.settings_spec = RSTParser.settings_spec - input_class = app.registry.get_source_input(filetype) - if input_class: - # Sphinx-1.8 style - source = input_class(app, env, source=None, source_path=filename, # type: ignore - encoding=env.config.source_encoding) - pub = Publisher(reader=reader, - parser=parser, - writer=SphinxDummyWriter(), - source_class=SphinxDummySourceClass, # type: ignore - destination=NullOutput()) - pub.process_programmatic_settings(None, env.settings, None) - pub.set_source(source, filename) - else: - # Sphinx-2.0 style - pub = Publisher(reader=reader, - parser=parser, - writer=SphinxDummyWriter(), - source_class=SphinxFileInput, - destination=NullOutput()) - pub.process_programmatic_settings(None, env.settings, None) - pub.set_source(source_path=filename) - + pub = Publisher(reader=reader, + parser=parser, + writer=SphinxDummyWriter(), + source_class=SphinxFileInput, + destination=NullOutput()) + pub.process_programmatic_settings(None, env.settings, None) + pub.set_source(source_path=filename) pub.publish() return pub.document diff --git a/sphinx/locale/el/LC_MESSAGES/sphinx.po b/sphinx/locale/el/LC_MESSAGES/sphinx.po index 03f5d01fe..6c0fc667b 100644 --- a/sphinx/locale/el/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/el/LC_MESSAGES/sphinx.po @@ -3301,12 +3301,12 @@ msgstr "περισσότεροι από ένας στόχοι βρέθηκαν #: sphinx/transforms/post_transforms/__init__.py:171 #, python-format msgid "%s:%s reference target not found: %%(target)s" -msgstr "Ο %s:%s στόχος αναφοράς δεν βρέθηκε: %% (στόχος)" +msgstr "Ο %s:%s στόχος αναφοράς δεν βρέθηκε: %%(target)s" #: sphinx/transforms/post_transforms/__init__.py:174 #, python-format msgid "%r reference target not found: %%(target)s" -msgstr "ο στόχος αναφοράς %r δεν βρέθηκε: %%(στόχος)" +msgstr "ο στόχος αναφοράς %r δεν βρέθηκε: %%(target)s" #: sphinx/transforms/post_transforms/images.py:86 #, python-format diff --git a/sphinx/locale/es/LC_MESSAGES/sphinx.mo b/sphinx/locale/es/LC_MESSAGES/sphinx.mo index bd4be1841..fce55c7e0 100644 Binary files a/sphinx/locale/es/LC_MESSAGES/sphinx.mo and b/sphinx/locale/es/LC_MESSAGES/sphinx.mo differ diff --git a/sphinx/locale/es/LC_MESSAGES/sphinx.po b/sphinx/locale/es/LC_MESSAGES/sphinx.po index a01ae6c80..65ea746fe 100644 --- a/sphinx/locale/es/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/es/LC_MESSAGES/sphinx.po @@ -3306,12 +3306,12 @@ msgstr "más de un objetivo destino encontrado para 'cualquier' referencia cruza #: sphinx/transforms/post_transforms/__init__.py:171 #, python-format msgid "%s:%s reference target not found: %%(target)s" -msgstr "%s:%s destino de referencia no encontrada: %% (destino)s" +msgstr "%s:%s destino de referencia no encontrada: %%(target)s" #: sphinx/transforms/post_transforms/__init__.py:174 #, python-format msgid "%r reference target not found: %%(target)s" -msgstr "%r destino de referencia no encontrada: %% (destino)s" +msgstr "%r destino de referencia no encontrada: %%(target)s" #: sphinx/transforms/post_transforms/images.py:86 #, python-format diff --git a/sphinx/locale/hr/LC_MESSAGES/sphinx.po b/sphinx/locale/hr/LC_MESSAGES/sphinx.po index 20e336487..bd809f381 100644 --- a/sphinx/locale/hr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hr/LC_MESSAGES/sphinx.po @@ -3305,7 +3305,7 @@ msgstr "%s:%s reference target nije pronađen: %%(target)s" #: sphinx/transforms/post_transforms/__init__.py:174 #, python-format msgid "%r reference target not found: %%(target)s" -msgstr "%r referenca target nije pronađena: %% (target)" +msgstr "%r referenca target nije pronađena: %%(target)s" #: sphinx/transforms/post_transforms/images.py:86 #, python-format diff --git a/sphinx/registry.py b/sphinx/registry.py index 168583739..cd7a7f4a0 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -9,6 +9,7 @@ """ import traceback +import warnings from importlib import import_module from types import MethodType from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Tuple, Type, Union @@ -23,6 +24,7 @@ from pkg_resources import iter_entry_points from sphinx.builders import Builder from sphinx.config import Config +from sphinx.deprecation import RemovedInSphinx60Warning from sphinx.domains import Domain, Index, ObjType from sphinx.domains.std import GenericObject, Target from sphinx.environment import BuildEnvironment @@ -285,6 +287,9 @@ class SphinxComponentRegistry: return parser def get_source_input(self, filetype: str) -> "Type[Input]": + warnings.warn('SphinxComponentRegistry.get_source_input() is deprecated.', + RemovedInSphinx60Warning) + try: return self.source_inputs[filetype] except KeyError: diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py index dab19547e..a508c50a1 100644 --- a/sphinx/setup_command.py +++ b/sphinx/setup_command.py @@ -190,6 +190,6 @@ class BuildDoc(Command): if not self.link_index: continue - src = app.config.master_doc + app.builder.out_suffix # type: ignore + src = app.config.root_doc + app.builder.out_suffix # type: ignore dst = app.builder.get_outfilename('index') # type: ignore os.symlink(src, dst) diff --git a/sphinx/templates/htmlhelp/project.hhc b/sphinx/templates/htmlhelp/project.hhc index c1096e711..705cfeba7 100644 --- a/sphinx/templates/htmlhelp/project.hhc +++ b/sphinx/templates/htmlhelp/project.hhc @@ -18,7 +18,7 @@