diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2021-01-24 16:34:47 +0900 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2021-01-24 16:34:47 +0900 |
commit | 51d500833e391c182f536e83a5d62d5e90ce8ca9 (patch) | |
tree | fb854309b759773feb83e7e4bbc91e3ed3cb2b00 | |
parent | 375fb52fe402d46d633e321ce8f20c1aa61c49b9 (diff) | |
parent | 41ee2d6e6595d0eefb4a2b752fd79a3451382d5a (diff) | |
download | sphinx-git-51d500833e391c182f536e83a5d62d5e90ce8ca9.tar.gz |
Merge branch '3.x' into 7774_remove_develop.rst
610 files changed, 17982 insertions, 4873 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 7f4de4ae0..9ded24cff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,12 +3,14 @@ jobs: build: docker: - image: sphinxdoc/docker-ci + environment: + DO_EPUBCHECK: 1 working_directory: /sphinx steps: - checkout - run: /python3.6/bin/pip install -U pip setuptools - run: /python3.6/bin/pip install -U .[test] - run: mkdir -p test-reports/pytest - - run: make test PYTHON=/python3.6/bin/python TEST=--junitxml=test-reports/pytest/results.xml + - run: make test PYTHON=/python3.6/bin/python TEST="--junitxml=test-reports/pytest/results.xml -vv" - store_test_results: path: test-reports diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index c9009b90e..226532b79 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,5 +2,8 @@ blank_issues_enabled: false # default: true contact_links: - name: Question + url: https://stackoverflow.com/questions/tagged/python-sphinx + about: For Q&A purpose, please use Stackoverflow with the tag python-sphinx +- name: Discussion url: https://groups.google.com/forum/#!forum/sphinx-users - about: For Q&A purpose, please use sphinx-users mailing list. + about: For general discussion, please use sphinx-users mailing list. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6f4fe672f..c8f8969a1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,7 +7,7 @@ Subject: <short purpose of this pull request> - Critical or severe bugs: X.Y.Z - Others: X.Y - For more details, see https://www.sphinx-doc.org/en/master/devguide.html#branch-model + For more details, see https://www.sphinx-doc.org/en/master/internals/release-process.html#branch-model --> ### Feature or Bugfix diff --git a/.github/workflows/builddoc.yml b/.github/workflows/builddoc.yml new file mode 100644 index 000000000..809fb68e6 --- /dev/null +++ b/.github/workflows/builddoc.yml @@ -0,0 +1,21 @@ +name: Build document + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: 3.6 + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y graphviz + pip install -U tox + - name: Run Tox + run: tox -e docs diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..913abcedd --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,22 @@ +name: Lint source code + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + tool: [docslint, flake8, isort, mypy, twine] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: 3.6 + - name: Install dependencies + run: pip install -U tox + - name: Run Tox + run: tox -e ${{ matrix.tool }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa2c1154a..89dc8fde9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,9 +1,64 @@ -name: CI on Windows +name: CI on: [push, pull_request] jobs: - build: + ubuntu: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [py35, py36, py37, py38, py39] + os: [ubuntu-16.04] + include: + - name: py35 + python: 3.5 + docutils: du12 + - name: py36 + python: 3.6 + docutils: du13 + - name: py37 + python: 3.7 + docutils: du14 + - name: py38 + python: 3.8 + docutils: du15 + - name: py39 + python: 3.9 + docutils: du16 + coverage: "--cov ./ --cov-append --cov-config setup.cfg" + - name: py310-dev + python: 3.10-dev + docutils: du16 + os: ubuntu-latest # required + env: + PYTEST_ADDOPTS: ${{ matrix.coverage }} + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v2 + if: "!endsWith(matrix.python, '-dev')" + with: + python-version: ${{ matrix.python }} + - name: Set up Python ${{ matrix.python }} (deadsnakes) + uses: deadsnakes/action@v2.0.1 + if: endsWith(matrix.python, '-dev') + with: + python-version: ${{ matrix.python }} + - name: Check Python version + run: python --version + - name: Install graphviz + run: sudo apt-get install graphviz + - name: Install dependencies + run: pip install -U tox codecov + - name: Run Tox + run: tox -e ${{ matrix.docutils }} -- -vv + - name: codecov + uses: codecov/codecov-action@v1 + if: matrix.coverage + + windows: runs-on: windows-latest strategy: matrix: @@ -18,4 +73,4 @@ jobs: - name: Install dependencies run: pip install -U tox - name: Run Tox - run: tox -e py + run: tox -e py -- -vv diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 000000000..d7a7c95f1 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,21 @@ +name: CI (node.js) + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + env: + node-version: 10.7 + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ env.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ env.node-version }} + - run: npm install + - name: Run headless test + uses: GabrielBB/xvfb-action@v1 + with: + run: npm test diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 000000000..680a0e3b5 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,8 @@ +version: 2 +python: + version: 3 + install: + - method: pip + path: . + extra_requirements: + - docs diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3ceb2e3f2..000000000 --- a/.travis.yml +++ /dev/null @@ -1,54 +0,0 @@ -os: linux -dist: xenial -language: python -cache: pip - -env: - global: - - PYTHONFAULTHANDLER=x - - SKIP_LATEX_BUILD=1 - - IS_PYTHON=true - -jobs: - include: - - python: '3.5' - env: - - TOXENV=du12 - - python: '3.6' - env: - - TOXENV=du13 - - python: '3.7' - env: - - TOXENV=du14 - - python: '3.8' - env: - - TOXENV=du15 - - PYTEST_ADDOPTS="--cov ./ --cov-append --cov-config setup.cfg" - - python: 'nightly' - env: - - TOXENV=du16 - - python: '3.6' - env: TOXENV=docs - - python: '3.6' - env: TOXENV=docslint - - python: '3.6' - env: TOXENV=mypy - - python: '3.6' - env: TOXENV=flake8 - - - language: node_js - node_js: '10.7' - env: IS_PYTHON=false - services: xvfb - -install: - - "sudo apt-get install graphviz" - - if [ $IS_PYTHON = true ]; then pip install -U tox codecov; fi - - if [ $IS_PYTHON = false ]; then npm install; fi - -script: - - if [ $IS_PYTHON = true ]; then tox -- -v; fi - - if [ $IS_PYTHON = false ]; then npm test; fi - -after_success: - - if [[ -e .coverage ]]; then codecov -e $TOXENV; fi @@ -1,9 +1,555 @@ -Release 3.1.0 (in development) +Release 3.5.0 (in development) ============================== Dependencies ------------ +Incompatible changes +-------------------- + +* Update Underscore.js to 1.12.0 +* #6550: html: The config variable ``html_add_permalinks`` is replaced by + :confval:`html_permalinks` and :confval:`html_permalinks_icon` + +Deprecated +---------- + +* pending_xref node for viewcode extension +* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.broken`` +* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.good`` +* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.redirected`` +* ``sphinx.builders.linkcheck.node_line_or_0()`` +* ``sphinx.ext.autodoc.AttributeDocumenter.isinstanceattribute()`` +* ``sphinx.ext.autodoc.directive.DocumenterBridge.reporter`` +* ``sphinx.ext.autodoc.importer.get_module_members()`` +* ``sphinx.ext.autosummary.generate._simple_info()`` +* ``sphinx.ext.autosummary.generate._simple_warn()`` +* ``sphinx.writers.html.HTMLTranslator.permalink_text`` +* ``sphinx.writers.html5.HTML5Translator.permalink_text`` + +Features added +-------------- + +* #8022: autodoc: autodata and autoattribute directives does not show right-hand + value of the variable if docstring contains ``:meta hide-value:`` in + info-field-list +* #8514: autodoc: Default values of overloaded functions are taken from actual + implementation if they're ellipsis +* #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()` +* #6241: html: Allow to add JS/CSS files to the specific page when an extension + calls ``app.add_js_file()`` or ``app.add_css_file()`` on + :event:`html-page-context` event +* #6550: html: Allow to use HTML permalink texts via + :confval:`html_permalinks_icon` +* #8649: imgconverter: Skip availability check if builder supports the image + type +* #8573: napoleon: Allow to change the style of custom sections using + :confval:`napoleon_custom_styles` +* #8004: napoleon: Type definitions in Google style docstrings are rendered as + references when :confval:`napoleon_preprocess_types` enabled +* #6241: mathjax: Include mathjax.js only on the document using equations +* #8651: std domain: cross-reference for a rubric having inline item is broken +* #8681: viewcode: Support incremental build +* #8132: Add :confval:`project_copyright` as an alias of :confval:`copyright` +* #207: Now :confval:`highlight_language` supports multiple languages +* #2030: :rst:dir:`code-block` and :rst:dir:`literalinclude` supports automatic + dedent via no-argument ``:dedent:`` option +* C++, also hyperlink operator overloads in expressions and alias declarations. +* #8247: Allow production lists to refer to tokens from other production groups + +Bugs fixed +---------- + +* #8727: apidoc: namespace module file is not generated if no submodules there +* #741: autodoc: inherited-members doesn't work for instance attributes on super + class +* #8592: autodoc: ``:meta public:`` does not effect to variables +* #8594: autodoc: empty __all__ attribute is ignored +* #8315: autodoc: Failed to resolve struct.Struct type annotation +* #8652: autodoc: All variable comments in the module are ignored if the module + contains invalid type comments +* #8693: autodoc: Default values for overloaded functions are rendered as string +* #8306: autosummary: mocked modules are documented as empty page when using + :recursive: option +* #8618: html: kbd role produces incorrect HTML when compound-key separators (-, + + or ^) are used as keystrokes +* #8629: html: A type warning for html_use_opensearch is shown twice +* #8714: html: kbd role with "Caps Lock" rendered incorrectly +* #8665: html theme: Could not override globaltoc_maxdepth in theme.conf +* #4304: linkcheck: Fix race condition that could lead to checking the + availability of the same URL twice +* #8094: texinfo: image files on the different directory with document are not + copied +* #8720: viewcode: module pages are generated for epub on incremental build +* #8704: viewcode: anchors are generated in incremental build after singlehtml +* #8671: :confval:`highlight_options` is not working +* #8341: C, fix intersphinx lookup types for names in declarations. +* C, C++: in general fix intersphinx and role lookup types. +* #8683: :confval:`html_last_updated_fmt` does not support UTC offset (%z) +* #8683: :confval:`html_last_updated_fmt` generates wrong time zone for %Z +* #1112: ``download`` role creates duplicated copies when relative path is + specified +* #8735: LaTeX: wrong internal links in pdf to captioned code-blocks when + :confval:`numfig` is not True + +Testing +-------- + +Release 3.4.4 (in development) +============================== + +Dependencies +------------ + +Incompatible changes +-------------------- + +Deprecated +---------- + +Features added +-------------- + +Bugs fixed +---------- + +* #8655: autodoc: Failed to generate document if target module contains an + object that raises an exception on ``hasattr()`` +* C, ``expr`` role should start symbol lookup in the current scope. + +Testing +-------- + +Release 3.4.3 (released Jan 08, 2021) +===================================== + +Bugs fixed +---------- + +* #8655: autodoc: Failed to generate document if target module contains an + object that raises an exception on ``hasattr()`` + +Release 3.4.2 (released Jan 04, 2021) +===================================== + +Bugs fixed +---------- + +* #8164: autodoc: Classes that inherit mocked class are not documented +* #8602: autodoc: The ``autodoc-process-docstring`` event is emitted to the + non-datadescriptors unexpectedly +* #8616: autodoc: AttributeError is raised on non-class object is passed to + autoclass directive + +Release 3.4.1 (released Dec 25, 2020) +===================================== + +Bugs fixed +---------- + +* #8559: autodoc: AttributeError is raised when using forward-reference type + annotations +* #8568: autodoc: TypeError is raised on checking slots attribute +* #8567: autodoc: Instance attributes are incorrectly added to Parent class +* #8566: autodoc: The ``autodoc-process-docstring`` event is emitted to the + alias classes unexpectedly +* #8583: autodoc: Unnecessary object comparision via ``__eq__`` method +* #8565: linkcheck: Fix PriorityQueue crash when link tuples are not + comparable + +Release 3.4.0 (released Dec 20, 2020) +===================================== + +Incompatible changes +-------------------- + +* #8105: autodoc: the signature of class constructor will be shown for decorated + classes, not a signature of decorator + +Deprecated +---------- + +* The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()`` +* The ``no_docstring`` argument of + ``sphinx.ext.autodoc.Documenter.add_content()`` +* ``sphinx.ext.autodoc.Documenter.get_object_members()`` +* ``sphinx.ext.autodoc.DataDeclarationDocumenter`` +* ``sphinx.ext.autodoc.GenericAliasDocumenter`` +* ``sphinx.ext.autodoc.InstanceAttributeDocumenter`` +* ``sphinx.ext.autodoc.SlotsAttributeDocumenter`` +* ``sphinx.ext.autodoc.TypeVarDocumenter`` +* ``sphinx.ext.autodoc.importer._getannotations()`` +* ``sphinx.ext.autodoc.importer._getmro()`` +* ``sphinx.pycode.ModuleAnalyzer.parse()`` +* ``sphinx.util.osutil.movefile()`` +* ``sphinx.util.requests.is_ssl_error()`` + +Features added +-------------- + +* #8119: autodoc: Allow to determine whether a member not included in + ``__all__`` attribute of the module should be documented or not via + :event:`autodoc-skip-member` event +* #8219: autodoc: Parameters for generic class are not shown when super class is + a generic class and show-inheritance option is given (in Python 3.7 or above) +* autodoc: Add ``Documenter.config`` as a shortcut to access the config object +* autodoc: Add Optional[t] to annotation of function and method if a default + value equal to None is set. +* #8209: autodoc: Add ``:no-value:`` option to :rst:dir:`autoattribute` and + :rst:dir:`autodata` directive to suppress the default value of the variable +* #8460: autodoc: Support custom types defined by typing.NewType +* #8285: napoleon: Add :confval:`napoleon_attr_annotations` to merge type hints + on source code automatically if any type is specified in docstring +* #8236: napoleon: Support numpydoc's "Receives" section +* #6914: Add a new event :event:`warn-missing-reference` to custom warning + messages when failed to resolve a cross-reference +* #6914: Emit a detailed warning when failed to resolve a ``:ref:`` reference +* #6629: linkcheck: The builder now handles rate limits. See + :confval:`linkcheck_retry_on_rate_limit` for details. + +Bugs fixed +---------- + +* #7613: autodoc: autodoc does not respect __signature__ of the class +* #4606: autodoc: the location of the warning is incorrect for inherited method +* #8105: autodoc: the signature of class constructor is incorrect if the class + is decorated +* #8434: autodoc: :confval:`autodoc_type_aliases` does not effect to variables + and attributes +* #8443: autodoc: autodata directive can't create document for PEP-526 based + type annotated variables +* #8443: autodoc: autoattribute directive can't create document for PEP-526 + based uninitalized variables +* #8480: autodoc: autoattribute could not create document for __slots__ + attributes +* #8503: autodoc: autoattribute could not create document for a GenericAlias as + class attributes correctly +* #8534: autodoc: autoattribute could not create document for a commented + attribute in alias class +* #8452: autodoc: autodoc_type_aliases doesn't work when autodoc_typehints is + set to "description" +* #8541: autodoc: autodoc_type_aliases doesn't work for the type annotation to + instance attributes +* #8460: autodoc: autodata and autoattribute directives do not display type + information of TypeVars +* #8493: autodoc: references to builtins not working in class aliases +* #8522: autodoc: ``__bool__`` method could be called +* #8067: autodoc: A typehint for the instance variable having type_comment on + super class is not displayed +* #8545: autodoc: a __slots__ attribute is not documented even having docstring +* #741: autodoc: inherited-members doesn't work for instance attributes on super + class +* #8477: autosummary: non utf-8 reST files are generated when template contains + multibyte characters +* #8501: autosummary: summary extraction splits text after "el at." unexpectedly +* #8524: html: Wrong url_root has been generated on a document named "index" +* #8419: html search: Do not load ``language_data.js`` in non-search pages +* #8549: i18n: ``-D gettext_compact=0`` is no longer working +* #8454: graphviz: The layout option for graph and digraph directives don't work +* #8131: linkcheck: Use GET when HEAD requests cause Too Many Redirects, to + accommodate infinite redirect loops on HEAD +* #8437: Makefile: ``make clean`` with empty BUILDDIR is dangerous +* #8365: py domain: ``:type:`` and ``:rtype:`` gives false ambiguous class + lookup warnings +* #8352: std domain: Failed to parse an option that starts with bracket +* #8519: LaTeX: Prevent page brake in the middle of a seealso +* #8520: C, fix copying of AliasNode. + +Release 3.3.1 (released Nov 12, 2020) +===================================== + +Bugs fixed +---------- + +* #8372: autodoc: autoclass directive became slower than Sphinx-3.2 +* #7727: autosummary: raise PycodeError when documenting python package + without __init__.py +* #8350: autosummary: autosummary_mock_imports causes slow down builds +* #8364: C, properly initialize attributes in empty symbols. +* #8399: i18n: Put system locale path after the paths specified by configuration + +Release 3.3.0 (released Nov 02, 2020) +===================================== + +Deprecated +---------- + +* ``sphinx.builders.latex.LaTeXBuilder.usepackages`` +* ``sphinx.builders.latex.LaTeXBuilder.usepackages_afger_hyperref`` +* ``sphinx.ext.autodoc.SingledispatchFunctionDocumenter`` +* ``sphinx.ext.autodoc.SingledispatchMethodDocumenter`` + +Features added +-------------- + +* #8100: html: Show a better error message for failures on copying + html_static_files +* #8141: C: added a ``maxdepth`` option to :rst:dir:`c:alias` to insert + nested declarations. +* #8081: LaTeX: Allow to add LaTeX package via ``app.add_latex_package()`` until + just before writing .tex file +* #7996: manpage: Add :confval:`man_make_section_directory` to make a section + directory on build man page +* #8289: epub: Allow to suppress "duplicated ToC entry found" warnings from epub + builder using :confval:`suppress_warnings`. +* #8298: sphinx-quickstart: Add :option:`sphinx-quickstart --no-sep` option +* #8304: sphinx.testing: Register public markers in sphinx.testing.fixtures +* #8051: napoleon: use the obj role for all See Also items +* #8050: napoleon: Apply :confval:`napoleon_preprocess_types` to every field +* C and C++, show line numbers for previous declarations when duplicates are + detected. +* #8183: Remove substitution_reference nodes from doctree only on LaTeX builds + +Bugs fixed +---------- + +* #8085: i18n: Add support for having single text domain +* #6640: i18n: Failed to override system message translation +* #8143: autodoc: AttributeError is raised when False value is passed to + autodoc_default_options +* #8103: autodoc: functools.cached_property is not considered as a property +* #8190: autodoc: parsing error is raised if some extension replaces docstring + by string not ending with blank lines +* #8142: autodoc: Wrong constructor signature for the class derived from + typing.Generic +* #8157: autodoc: TypeError is raised when annotation has invalid __args__ +* #7964: autodoc: Tuple in default value is wrongly rendered +* #8200: autodoc: type aliases break type formatting of autoattribute +* #7786: autodoc: can't detect overloaded methods defined in other file +* #8294: autodoc: single-string __slots__ is not handled correctly +* #7785: autodoc: autodoc_typehints='none' does not effect to overloaded functions +* #8192: napoleon: description is disappeared when it contains inline literals +* #8142: napoleon: Potential of regex denial of service in google style docs +* #8169: LaTeX: pxjahyper loaded even when latex_engine is not platex +* #8215: LaTeX: 'oneside' classoption causes build warning +* #8175: intersphinx: Potential of regex denial of service by broken inventory +* #8277: sphinx-build: missing and redundant spacing (and etc) for console + output on building +* #7973: imgconverter: Check availability of imagemagick many times +* #8255: py domain: number in default argument value is changed from hexadecimal + to decimal +* #8316: html: Prevent arrow keys changing page when button elements are focused +* #8343: html search: Fix unnecessary load of images when parsing the document +* #8254: html theme: Line numbers misalign with code lines +* #8093: The highlight warning has wrong location in some builders (LaTeX, + singlehtml and so on) +* #8215: Eliminate Fancyhdr build warnings for oneside documents +* #8239: Failed to refer a token in productionlist if it is indented +* #8268: linkcheck: Report HTTP errors when ``linkcheck_anchors`` is ``True`` +* #8245: linkcheck: take source directory into account for local files +* #8321: linkcheck: ``tel:`` schema hyperlinks are detected as errors +* #8323: linkcheck: An exit status is incorrect when links having unsupported + schema found +* #8188: C, add missing items to internal object types dictionary, + e.g., preventing intersphinx from resolving them. +* C, fix anon objects in intersphinx. +* #8270, C++, properly reject functions as duplicate declarations if a + non-function declaration of the same name already exists. +* C, fix references to function parameters. + Link to the function instead of a non-existing anchor. +* #6914: figure numbers are unexpectedly assigned to uncaptioned items +* #8320: make "inline" line numbers un-selectable + +Testing +-------- + +* #8257: Support parallel build in sphinx.testing + +Release 3.2.1 (released Aug 14, 2020) +===================================== + +Features added +-------------- + +* #8095: napoleon: Add :confval:`napoleon_preprocess_types` to enable the type + preprocessor for numpy style docstrings +* #8114: C and C++, parse function attributes after parameters and qualifiers. + +Bugs fixed +---------- + +* #8074: napoleon: Crashes during processing C-ext module +* #8088: napoleon: "Inline literal start-string without end-string" warning in + Numpy style Parameters section +* #8084: autodoc: KeyError is raised on documenting an attribute of the broken + class +* #8091: autodoc: AttributeError is raised on documenting an attribute on Python + 3.5.2 +* #8099: autodoc: NameError is raised when target code uses ``TYPE_CHECKING`` +* C++, fix parsing of template template paramters, broken by the fix of #7944 + +Release 3.2.0 (released Aug 08, 2020) +===================================== + +Deprecated +---------- + +* ``sphinx.ext.autodoc.members_set_option()`` +* ``sphinx.ext.autodoc.merge_special_members_option()`` +* ``sphinx.writers.texinfo.TexinfoWriter.desc`` +* C, parsing of pre-v3 style type directives and roles, along with the options + :confval:`c_allow_pre_v3` and :confval:`c_warn_on_allowed_pre_v3`. + +Features added +-------------- + +* #2076: autodoc: Allow overriding of exclude-members in skip-member function +* #8034: autodoc: ``:private-member:`` can take an explicit list of member names + to be documented +* #2024: autosummary: Add :confval:`autosummary_filename_map` to avoid conflict + of filenames between two object with different case +* #8011: autosummary: Support instance attributes as a target of autosummary + directive +* #7849: html: Add :confval:`html_codeblock_linenos_style` to change the style + of line numbers for code-blocks +* #7853: C and C++, support parameterized GNU style attributes. +* #7888: napoleon: Add aliases Warn and Raise. +* #7690: napoleon: parse type strings and make them hyperlinks as possible. The + conversion rule can be updated via :confval:`napoleon_type_aliases` +* #8049: napoleon: Create a hyperlink for each the type of parameter when + :confval:`napoleon_use_params` is False +* C, added :rst:dir:`c:alias` directive for inserting copies + of existing declarations. +* #7745: html: inventory is broken if the docname contains a space +* #7991: html search: Allow searching for numbers +* #7902: html theme: Add a new option :confval:`globaltoc_maxdepth` to control + the behavior of globaltoc in sidebar +* #7840: i18n: Optimize the dependencies check on bootstrap +* #7768: i18n: :confval:`figure_language_filename` supports ``docpath`` token +* #5208: linkcheck: Support checks for local links +* #5090: setuptools: Link verbosity to distutils' -v and -q option +* #6698: doctest: Add ``:trim-doctest-flags:`` and ``:no-trim-doctest-flags:`` + options to doctest, testcode and testoutput directives +* #7052: add ``:noindexentry:`` to the Python, C, C++, and Javascript domains. + Update the documentation to better reflect the relationship between this option + and the ``:noindex:`` option. +* #7899: C, add possibility of parsing of some pre-v3 style type directives and + roles and try to convert them to equivalent v3 directives/roles. + Set the new option :confval:`c_allow_pre_v3` to ``True`` to enable this. + The warnings printed from this functionality can be suppressed by setting + :confval:`c_warn_on_allowed_pre_v3`` to ``True``. + The functionality is immediately deprecated. +* #7999: C, add support for named variadic macro arguments. +* #8071: Allow to suppress "self referenced toctrees" warning + +Bugs fixed +---------- + +* #7886: autodoc: TypeError is raised on mocking generic-typed classes +* #7935: autodoc: function signature is not shown when the function has a + parameter having ``inspect._empty`` as its default value +* #7901: autodoc: type annotations for overloaded functions are not resolved +* #904: autodoc: An instance attribute cause a crash of autofunction directive +* #1362: autodoc: ``private-members`` option does not work for class attributes +* #7983: autodoc: Generator type annotation is wrongly rendered in py36 +* #8030: autodoc: An uninitialized annotated instance variable is not documented + when ``:inherited-members:`` option given +* #8032: autodoc: A type hint for the instance variable defined at parent class + is not shown in the document of the derived class +* #8041: autodoc: An annotated instance variable on super class is not + documented when derived class has other annotated instance variables +* #7839: autosummary: cannot handle umlauts in function names +* #7865: autosummary: Failed to extract summary line when abbreviations found +* #7866: autosummary: Failed to extract correct summary line when docstring + contains a hyperlink target +* #7469: autosummary: "Module attributes" header is not translatable +* #7940: apidoc: An extra newline is generated at the end of the rst file if a + module has submodules +* #4258: napoleon: decorated special methods are not shown +* #7799: napoleon: parameters are not escaped for combined params in numpydoc +* #7780: napoleon: multiple paramaters declaration in numpydoc was wrongly + recognized when napoleon_use_params=True +* #7715: LaTeX: ``numfig_secnum_depth > 1`` leads to wrong figure links +* #7846: html theme: XML-invalid files were generated +* #7894: gettext: Wrong source info is shown when using rst_epilog +* #7691: linkcheck: HEAD requests are not used for checking +* #4888: i18n: Failed to add an explicit title to ``:ref:`` role on translation +* #7928: py domain: failed to resolve a type annotation for the attribute +* #8008: py domain: failed to parse a type annotation containing ellipsis +* #7994: std domain: option directive does not generate old node_id compatible + with 2.x or older +* #7968: i18n: The content of ``math`` directive is interpreted as reST on + translation +* #7768: i18n: The ``root`` element for :confval:`figure_language_filename` is + not a path that user specifies in the document +* #7993: texinfo: TypeError is raised for nested object descriptions +* #7993: texinfo: a warning not supporting desc_signature_line node is shown +* #7869: :rst:role:`abbr` role without an explanation will show the explanation + from the previous abbr role +* #8048: graphviz: graphviz.css was copied on building non-HTML document +* C and C++, removed ``noindex`` directive option as it did + nothing. +* #7619: Duplicated node IDs are generated if node has multiple IDs +* #2050: Symbols sections are appeared twice in the index page +* #8017: Fix circular import in sphinx.addnodes +* #7986: CSS: make "highlight" selector more robust +* #7944: C++, parse non-type template parameters starting with + a dependent qualified name. +* C, don't deepcopy the entire symbol table and make a mess every time an + enumerator is handled. + +Release 3.1.2 (released Jul 05, 2020) +===================================== + +Incompatible changes +-------------------- + +* #7650: autodoc: the signature of base function will be shown for decorated + functions, not a signature of decorator + +Bugs fixed +---------- + +* #7844: autodoc: Failed to detect module when relative module name given +* #7856: autodoc: AttributeError is raised when non-class object is given to + the autoclass directive +* #7850: autodoc: KeyError is raised for invalid mark up when autodoc_typehints + is 'description' +* #7812: autodoc: crashed if the target name matches to both an attribute and + module that are same name +* #7650: autodoc: function signature becomes ``(*args, **kwargs)`` if the + function is decorated by generic decorator +* #7812: autosummary: generates broken stub files if the target code contains + an attribute and module that are same name +* #7806: viewcode: Failed to resolve viewcode references on 3rd party builders +* #7838: html theme: List items have extra vertical space +* #7878: html theme: Undesired interaction between "overflow" and "float" + +Release 3.1.1 (released Jun 14, 2020) +===================================== + +Incompatible changes +-------------------- + +* #7808: napoleon: a type for attribute are represented as typed field + +Features added +-------------- + +* #7807: autodoc: Show detailed warning when type_comment is mismatched with its + signature + +Bugs fixed +---------- + +* #7808: autodoc: Warnings raised on variable and attribute type annotations +* #7802: autodoc: EOFError is raised on parallel build +* #7821: autodoc: TypeError is raised for overloaded C-ext function +* #7805: autodoc: an object which descriptors returns is unexpectedly documented +* #7807: autodoc: wrong signature is shown for the function using contextmanager +* #7812: autosummary: generates broken stub files if the target code contains + an attribute and module that are same name +* #7808: napoleon: Warnings raised on variable and attribute type annotations +* #7811: sphinx.util.inspect causes circular import problem + +Release 3.1.0 (released Jun 08, 2020) +===================================== + +Dependencies +------------ + * #7746: mathjax: Update to 2.7.5 Incompatible changes @@ -51,6 +597,8 @@ Features added builtin base classes * #2106: autodoc: Support multiple signatures on docstring * #4422: autodoc: Support GenericAlias in Python 3.7 or above +* #3610: autodoc: Support overloaded functions +* #7722: autodoc: Support TypeVar * #7466: autosummary: headings in generated documents are not translated * #7490: autosummary: Add ``:caption:`` option to autosummary directive to set a caption to the toctree @@ -61,7 +609,8 @@ Features added variables for custom templates * #7530: html: Support nested <kbd> elements * #7481: html theme: Add right margin to footnote/citation labels -* #7482: html theme: CSS spacing for code blocks with captions and line numbers +* #7482, #7717: html theme: CSS spacing for code blocks with captions and line + numbers * #7443: html theme: Add new options :confval:`globaltoc_collapse` and :confval:`globaltoc_includehidden` to control the behavior of globaltoc in sidebar @@ -73,6 +622,8 @@ Features added * #7542: html theme: Make admonition/topic/sidebar scrollable * #7543: html theme: Add top and bottom margins to tables * #7695: html theme: Add viewport meta tag for basic theme +* #7721: html theme: classic: default codetextcolor/codebgcolor doesn't override + Pygments * C and C++: allow semicolon in the end of declarations. * C++, parse parameterized noexcept specifiers. * #7294: C++, parse expressions with user-defined literals. @@ -80,8 +631,13 @@ Features added * #7143: py domain: Add ``:final:`` option to :rst:dir:`py:class:`, :rst:dir:`py:exception:` and :rst:dir:`py:method:` directives * #7596: py domain: Change a type annotation for variables to a hyperlink +* #7770: std domain: :rst:dir:`option` directive support arguments in the form + of ``foo[=bar]`` * #7582: napoleon: a type for attribute are represented like type annotation * #7734: napoleon: overescaped trailing underscore on attribute +* #7247: linkcheck: Add :confval:`linkcheck_request_headers` to send custom HTTP + headers for specific host +* #7792: setuptools: Support ``--verbosity`` option * #7683: Add ``allowed_exceptions`` parameter to ``Sphinx.emit()`` to allow handlers to raise specified exceptions * #7295: C++, parse (trailing) requires clauses. @@ -113,6 +669,7 @@ Bugs fixed * #7668: autodoc: wrong retann value is passed to a handler of autodoc-proccess-signature * #7711: autodoc: fails with ValueError when processing numpy objects +* #7791: autodoc: TypeError is raised on documenting singledispatch function * #7551: autosummary: a nested class is indexed as non-nested class * #7661: autosummary: autosummary directive emits warnings twices if failed to import the target module @@ -121,8 +678,12 @@ Bugs fixed * #7671: autosummary: The location of import failure warning is missing * #7535: sphinx-autogen: crashes when custom template uses inheritance * #7536: sphinx-autogen: crashes when template uses i18n feature +* #7781: sphinx-build: Wrong error message when outdir is not directory * #7653: sphinx-quickstart: Fix multiple directory creation for nested relpath * #2785: html: Bad alignment of equation links +* #7718: html theme: some themes does not respect background color of Pygments + style (agogo, haiku, nature, pyramid, scrolls, sphinxdoc and traditional) +* #7544: html theme: inconsistent padding in admonitions * #7581: napoleon: bad parsing of inline code in attribute docstrings * #7628: imgconverter: runs imagemagick once unnecessary for builders not supporting images @@ -130,7 +691,10 @@ Bugs fixed * #7646: handle errors on event handlers * #4187: LaTeX: EN DASH disappears from PDF bookmarks in Japanese documents * #7701: LaTeX: Anonymous indirect hyperlink target causes duplicated labels +* #7723: LaTeX: pdflatex crashed when URL contains a single quote * #7756: py domain: The default value for positional only argument is not shown +* #7760: coverage: Add :confval:`coverage_show_missing_items` to show coverage + result to console * C++, fix rendering and xrefs in nested names explicitly starting in global scope, e.g., ``::A::B``. * C, fix rendering and xrefs in nested names explicitly starting @@ -138,30 +702,6 @@ Bugs fixed * #7763: C and C++, don't crash during display stringification of unary expressions and fold expressions. -Testing --------- - -Release 3.0.5 (in development) -============================== - -Dependencies ------------- - -Incompatible changes --------------------- - -Deprecated ----------- - -Features added --------------- - -Bugs fixed ----------- - -Testing --------- - Release 3.0.4 (released May 27, 2020) ===================================== @@ -470,7 +1010,7 @@ Release 2.4.1 (released Feb 11, 2020) Bugs fixed ---------- -* #7120: html: crashed when on scaling SVG images which have float dimentions +* #7120: html: crashed when on scaling SVG images which have float dimensions * #7126: autodoc: TypeError: 'getset_descriptor' object is not iterable Release 2.4.0 (released Feb 09, 2020) @@ -616,7 +1156,7 @@ Features added * #6548: html: Use favicon for OpenSearch if available * #6729: html theme: agogo theme now supports ``rightsidebar`` option * #6780: Add PEP-561 Support -* #6762: latex: Allow to load additonal LaTeX packages via ``extrapackages`` key +* #6762: latex: Allow to load additional LaTeX packages via ``extrapackages`` key of :confval:`latex_elements` * #1331: Add new config variable: :confval:`user_agent` * #6000: LaTeX: have backslash also be an inline literal word wrap break diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 73ea1e52e..bd164694d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -8,10 +8,11 @@ reports/feature requests. Our contributing guide can be found online at: -https://www.sphinx-doc.org/en/master/internals/contributing/ +https://www.sphinx-doc.org/en/master/internals/contributing.html You can also browse it from this repository from -``doc/internals/contributing/`` +``doc/internals/contributing.rst`` Sphinx uses GitHub to host source code, track patches and bugs, and more. -Please make an effort to provide as much possible when filing bugs. +Please make an effort to provide as much detail as possible when filing +bugs. @@ -230,6 +230,7 @@ Documentation using sphinx_rtd_theme * `MyHDL <http://docs.myhdl.org/>`__ * `Nextflow <https://www.nextflow.io/docs/latest/index.html>`__ * `NICOS <https://forge.frm2.tum.de/nicos/doc/nicos-master/>`__ (customized) +* `OpenFAST <https://openfast.readthedocs.io/>`__ * `Pelican <http://docs.getpelican.com/>`__ * `picamera <https://picamera.readthedocs.io/>`__ * `Pillow <https://pillow.readthedocs.io/>`__ @@ -317,6 +318,7 @@ Documentation using a custom theme or integrated in a website * `Django <https://docs.djangoproject.com/>`__ * `Doctrine <https://www.doctrine-project.org/>`__ * `Enterprise Toolkit for Acrobat products <https://www.adobe.com/devnet-docs/acrobatetk/>`__ +* `FreeFEM <https://doc.freefem.org/introduction/>`__ * `Gameduino <http://excamera.com/sphinx/gameduino/>`__ * `gensim <https://radimrehurek.com/gensim/>`__ * `GeoServer <http://docs.geoserver.org/>`__ @@ -330,6 +332,7 @@ Documentation using a custom theme or integrated in a website * `Lasso <http://lassoguide.com/>`__ * `Mako <http://docs.makotemplates.org/>`__ * `MirrorBrain <http://mirrorbrain.org/docs/>`__ +* `Mitiq <https://mitiq.readthedocs.io/>`__ * `MongoDB <https://docs.mongodb.com/>`__ * `Music21 <https://web.mit.edu/music21/doc/>`__ * `MyHDL <http://docs.myhdl.org/>`__ @@ -355,7 +358,7 @@ Documentation using a custom theme or integrated in a website * `Roundup <http://www.roundup-tracker.org/>`__ * `SaltStack <https://docs.saltstack.com/>`__ * `scikit-learn <http://scikit-learn.org/stable/>`__ -* `SciPy <https://docs.scipy.org/doc/scipy/refrence/>`__ +* `SciPy <https://docs.scipy.org/doc/scipy/reference/>`__ * `Scrapy <https://doc.scrapy.org/>`__ * `Seaborn <https://seaborn.pydata.org/>`__ * `Selenium <https://docs.seleniumhq.org/docs/>`__ @@ -382,6 +385,7 @@ Homepages and other non-documentation sites * `Pylearn2 <http://www.deeplearning.net/software/pylearn2/>`__ (sphinxdoc, customized) * `PyXLL <https://www.pyxll.com/>`__ (sphinx_bootstrap_theme, customized) * `SciPy Cookbook <https://scipy-cookbook.readthedocs.io/>`__ (sphinx_rtd_theme) +* `Tech writer at work blog <https://blog.documatt.com/>`__ (custom theme) * `The Wine Cellar Book <https://www.thewinecellarbook.com/doc/en/>`__ (sphinxdoc) * `Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials <https://thomas-cokelaer.info/tutorials/>`__ (standard) * `UC Berkeley ME233 Advanced Control Systems II course <https://berkeley-me233.github.io/>`__ (sphinxdoc) @@ -1,7 +1,7 @@ License for Sphinx ================== -Copyright (c) 2007-2019 by the Sphinx team (see AUTHORS file). +Copyright (c) 2007-2021 by the Sphinx team (see AUTHORS file). All rights reserved. Redistribution and use in source and binary forms, with or without @@ -64,17 +64,13 @@ type-check: doclinter: python utils/doclinter.py CHANGES *.rst doc/ -.PHONY: pylint -pylint: - @pylint --rcfile utils/pylintrc sphinx - .PHONY: test test: - @$(PYTHON) -m pytest -v $(TEST) + @$(PYTHON) -X dev -m pytest -v $(TEST) .PHONY: covertest covertest: - @$(PYTHON) -m pytest -v --cov=sphinx --junitxml=.junit.xml $(TEST) + @$(PYTHON) -X dev -m pytest -v --cov=sphinx --junitxml=.junit.xml $(TEST) .PHONY: build build: @@ -83,6 +79,6 @@ build: .PHONY: docs docs: ifndef target - $(info You need to give a provide a target variable, e.g. `make docs target=html`.) + $(info You need to provide a target variable, e.g. `make docs target=html`.) endif $(MAKE) -C doc $(target) diff --git a/README.rst b/README.rst index b99b79702..13bbab99d 100644 --- a/README.rst +++ b/README.rst @@ -30,6 +30,10 @@ :target: https://opensource.org/licenses/BSD-3-Clause :alt: BSD 3 Clause +.. image:: https://codetriage.com/sphinx-doc/sphinx/badges/users.svg + :target: https://codetriage.com/sphinx-doc/sphinx + :alt: Open Source Helpers badge + Sphinx is a tool that makes it easy to create intelligent and beautiful documentation for Python projects (or other documents consisting of multiple reStructuredText sources), written by Georg Brandl. It was originally created diff --git a/bindep.txt b/bindep.txt index b99782017..dfee52c28 100644 --- a/bindep.txt +++ b/bindep.txt @@ -13,3 +13,9 @@ texlive-anyfontsize [platform:rpm] texlive-ctablestack [platform:rpm] texlive-gnu-freefont [platform:rpm] latexmk [platform:rpm] + +texlive-latex-recommended [platform:dpkg] +texlive-fonts-recommended [platform:dpkg] +texlive-latex-extra [platform:dpkg] +texlive-luatex [platform:dpkg] +latexmk [platform:dpkg] diff --git a/doc/_static/Makefile b/doc/_static/Makefile index e8793874c..8c880bcb2 100644 --- a/doc/_static/Makefile +++ b/doc/_static/Makefile @@ -1,4 +1,6 @@ +translation.png: translation.puml + plantuml -tpng $< translation.svg: translation.puml plantuml -tsvg $< clean: - rm translation.svg + rm -f translation.png translation.svg diff --git a/doc/_static/favicon.svg b/doc/_static/favicon.svg new file mode 100644 index 000000000..c3e1acd35 --- /dev/null +++ b/doc/_static/favicon.svg @@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> + <style> + @media (prefers-color-scheme: dark) { + svg { fill: white; } + } + </style> + <path d="m 67.780707,71.526216 c 0,-2.720856 0.735772,-7.633735 1.635035,-10.917507 2.076574,-7.582764 3.222746,-16.97568 2.071477,-16.97568 -0.485619,0 -3.994408,3.173002 -7.797313,7.051115 -14.448869,14.734603 -29.952812,23.068339 -42.915946,23.068339 -7.400211,0 -12.4298817,-1.871115 -17.2867007,-6.430912 -2.94436186,-2.764297 -3.47532146,-4.129685 -3.47532146,-8.936928 0,-4.94488 0.4862322,-6.108589 3.78321146,-9.054437 2.987989,-2.669773 4.875111,-3.380296 8.9779137,-3.380296 3.163221,0.711278 5.032659,0.664017 6.063532,1.917191 1.045041,1.231842 1.406892,5.262673 0.143323,7.623675 -0.674746,1.260763 -2.435471,2.043539 -4.5966,2.043539 -2.040303,0 -3.203991,-0.483702 -2.786976,-1.15844 1.31395,-2.126021 -0.560952,-3.566616 -2.9664067,-2.279256 -2.907025,1.555792 -2.957418,7.069066 -0.08839,9.665535 4.0345357,3.651203 15.1912207,5.023925 21.9019857,2.694828 7.250749,-2.516503 16.739014,-8.578986 24.30831,-15.531674 l 6.657407,-6.115083 -8.688303,-0.05007 C 43.622519,44.707714 37.702703,43.621524 18.54695,38.489741 12.175528,36.782852 6.0502733,35.306342 4.9352743,35.208608 3.6710803,35.097791 2.841723,34.067882 2.9080043,32.476074 3.0199286,29.788108 4.4800823,27.78768 6.2067673,27.033038 7.2437505,26.579828 14.43583,25.894406 22.0605,23.866486 c 29.699148,-7.899023 31.502043,-6.781254 51.28707,-1.772167 6.461504,1.635896 13.942408,3.414988 17.256961,3.474566 5.106245,0.09178 6.211825,0.514653 7.240255,2.76932 0.66758,1.46355 1.21378,2.858905 1.21378,3.10079 0,0.241884 -2.89333,1.764397 -6.429613,3.383363 -12.984983,5.944723 -17.083271,9.093943 -12.855172,15.130399 1.753219,2.503069 1.718037,2.768923 -0.57922,4.37799 -1.345193,0.942203 -2.457238,2.856456 -2.471232,4.253898 -0.03777,3.776976 -2.424786,11.884847 -5.893734,15.080164 l -3.048923,2.808424 z m 6.632814,-34.658372 c 5.169656,-1.440693 8.302047,-3.07045 14.72913,-6.500861 -5.292267,-1.548658 -18.570782,-3.724097 -18.570782,-3.724097 -9.796513,-1.964547 -8.76916,-1.865132 -9.21348,0.29669 -0.176673,0.859598 -0.702644,2.763948 -1.872329,4.596663 -2.251474,3.527711 -10.489307,4.271075 -15.214327,2.009703 -1.482367,-0.709454 -2.971272,-3.416276 -2.950606,-5.336922 0.02911,-2.705486 -1.505386,-3.336055 -2.486689,-2.975309 -0.796428,0.292781 -3.384665,0.330004 -9.071284,1.864262 -18.784765,5.068157 -21.3552119,4.487473 -9.110967,6.223299 1.472409,0.208739 9.252992,2.381926 13.052028,3.39412 9.318588,2.482796 11.064717,2.665087 23.125496,2.414247 8.385835,-0.174409 11.891174,-0.675356 17.58381,-2.261795 z M 3.0589449,14.916483 C 3.2921927,12.514245 3.424378,11.992797 10.100599,10.647894 13.924923,9.8774962 23.355266,7.3808108 31.056903,5.0997052 c 17.703937,-5.2436279 22.73392,-5.2565016 41.092202,-0.105175 7.923233,2.2232606 16.798382,4.047803 19.72254,4.054541 4.567242,0.01054 6.941892,2.0284768 6.941892,2.0284768 2.101843,4.825342 1.718463,5.158474 -6.484103,5.158474 -5.714193,0 -10.641875,-0.963081 -18.245438,-3.565943 C 68.300078,10.69012 60.060462,8.8316882 55.557963,8.4915615 47.342337,7.8709375 47.353713,7.8687835 21.963188,14.855617 17.503192,16.082896 11.34213,17.454164 8.2719268,17.902883 l -5.5821654,0.81585 z" /> +</svg> diff --git a/doc/_static/translation.png b/doc/_static/translation.png Binary files differnew file mode 100644 index 000000000..002b3d1f3 --- /dev/null +++ b/doc/_static/translation.png diff --git a/doc/_static/translation.puml b/doc/_static/translation.puml index 5c3a7350b..7b8fc9f59 100644 --- a/doc/_static/translation.puml +++ b/doc/_static/translation.puml @@ -12,5 +12,5 @@ SphinxProject -r-> .rst .pot -r-> .po : Pootle .po -d-> .mo : msgfmt .mo -l-> TranslatedBuild -.rst -d-> TranslatedBuild : "sphinx-buid -Dlanguage=" +.rst -d-> TranslatedBuild : "sphinx-build -Dlanguage=" @enduml diff --git a/doc/_static/translation.svg b/doc/_static/translation.svg index 74b78a1e7..4e3ab5ab4 100644 --- a/doc/_static/translation.svg +++ b/doc/_static/translation.svg @@ -1,4 +1,18 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="224px" preserveAspectRatio="none" style="width:602px;height:224px;" version="1.1" viewBox="0 0 602 224" width="602px" zoomAndPan="magnify"><defs><filter height="300%" id="f7a11izs19byb" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--entity SphinxProject--><polygon fill="#FEFECE" filter="url(#f7a11izs19byb)" points="6,31.5,6,67.5986,112,67.5986,112,41.5,102,31.5,6,31.5" style="stroke: #000000; stroke-width: 1.5;"/><path d="M102,31.5 L102,41.5 L112,41.5 " fill="#FEFECE" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="86" x="16" y="54.6318">SphinxProject</text><!--entity .rst--><polygon fill="#FEFECE" filter="url(#f7a11izs19byb)" points="147,31.5,147,67.5986,187,67.5986,187,41.5,177,31.5,147,31.5" style="stroke: #000000; stroke-width: 1.5;"/><path d="M177,31.5 L177,41.5 L187,41.5 " fill="#FEFECE" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="20" x="157" y="54.6318">.rst</text><!--entity .pot--><path d="M337,37 C337,27 359,27 359,27 C359,27 381,27 381,37 L381,62.0986 C381,72.0986 359,72.0986 359,72.0986 C359,72.0986 337,72.0986 337,62.0986 L337,37 " fill="#FEFECE" filter="url(#f7a11izs19byb)" style="stroke: #000000; stroke-width: 1.5;"/><path d="M337,37 C337,47 359,47 359,47 C359,47 381,47 381,37 " fill="none" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="24" x="347" y="64.1318">.pot</text><!--entity .po--><path d="M455,37 C455,27 475,27 475,27 C475,27 495,27 495,37 L495,62.0986 C495,72.0986 475,72.0986 475,72.0986 C475,72.0986 455,72.0986 455,62.0986 L455,37 " fill="#FEFECE" filter="url(#f7a11izs19byb)" style="stroke: #000000; stroke-width: 1.5;"/><path d="M455,37 C455,47 475,47 475,47 C475,47 495,47 495,37 " fill="none" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="20" x="465" y="64.1318">.po</text><!--entity .mo--><path d="M373.5,177 C373.5,167 395,167 395,167 C395,167 416.5,167 416.5,177 L416.5,202.0986 C416.5,212.0986 395,212.0986 395,212.0986 C395,212.0986 373.5,212.0986 373.5,202.0986 L373.5,177 " fill="#FEFECE" filter="url(#f7a11izs19byb)" style="stroke: #000000; stroke-width: 1.5;"/><path d="M373.5,177 C373.5,187 395,187 395,187 C395,187 416.5,187 416.5,177 " fill="none" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="23" x="383.5" y="204.1318">.mo</text><!--entity translator--><ellipse cx="560" cy="18" fill="#FEFECE" filter="url(#f7a11izs19byb)" rx="8" ry="8" style="stroke: #A80036; stroke-width: 2.0;"/><path d="M560,26 L560,53 M547,34 L573,34 M560,53 L547,68 M560,53 L573,68 " fill="none" filter="url(#f7a11izs19byb)" style="stroke: #A80036; stroke-width: 2.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="60" x="530" y="88.1318">translator</text><!--entity TranslatedBuild--><polygon fill="#FEFECE" filter="url(#f7a11izs19byb)" points="202.5,171.5,202.5,207.5986,321.5,207.5986,321.5,181.5,311.5,171.5,202.5,171.5" style="stroke: #000000; stroke-width: 1.5;"/><path d="M311.5,171.5 L311.5,181.5 L321.5,181.5 " fill="#FEFECE" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="99" x="212.5" y="194.6318">TranslatedBuild</text><!--link .po to translator--><path d="M500.3972,49.5 C510.2325,49.5 520.0678,49.5 529.9032,49.5 " fill="none" id=".po-translator" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="495.2539,49.5,504.2539,53.5,500.2539,49.5,504.2539,45.5,495.2539,49.5" style="stroke: #A80036; stroke-width: 1.0;"/><!--link SphinxProject to .rst--><path d="M112.1563,49.5 C122.0076,49.5 131.859,49.5 141.7104,49.5 " fill="none" id="SphinxProject-.rst" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="146.8621,49.5,137.8621,45.5,141.8621,49.5,137.8621,53.5,146.8621,49.5" style="stroke: #A80036; stroke-width: 1.0;"/><!--link .rst to .pot--><path d="M187.1845,49.5 C221.8302,49.5 292.6458,49.5 331.676,49.5 " fill="none" id=".rst-.pot" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="336.7347,49.5,327.7347,45.5,331.7347,49.5,327.7347,53.5,336.7347,49.5" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="113" x="205.5" y="43.6938">sphinx-build gettext</text><!--link .pot to .po--><path d="M381.0918,49.5 C400.726,49.5 429.4114,49.5 449.9055,49.5 " fill="none" id=".pot-.po" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="454.9288,49.5,445.9288,45.5,449.9288,49.5,445.9288,53.5,454.9288,49.5" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="37" x="399.5" y="43.6938">Pootle</text><!--link .po to .mo--><path d="M461.9686,72.305 C447.9056,96.9151 425.5182,136.0932 410.5467,162.2933 " fill="none" id=".po-.mo" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="408.0259,166.7048,415.9642,160.8753,410.5066,162.3636,409.0183,156.9061,408.0259,166.7048" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="43" x="434" y="134.1938">msgfmt</text><!--link TranslatedBuild to .mo--><path d="M326.9772,189.5 C342.4024,189.5 357.8276,189.5 373.2527,189.5 " fill="none" id="TranslatedBuild-.mo" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="321.7461,189.5,330.7461,193.5,326.7461,189.5,330.7461,185.5,321.7461,189.5" style="stroke: #A80036; stroke-width: 1.0;"/><!--link .rst to TranslatedBuild--><path d="M179.2251,67.5159 C196.4449,92.8925 227.8341,139.1503 246.6178,166.8315 " fill="none" id=".rst-TranslatedBuild" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="249.5202,171.1086,247.7765,161.4153,246.7127,166.9712,241.1568,165.9074,249.5202,171.1086" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="143" x="227" y="134.1938">sphinx-buid -Dlanguage=</text><!-- +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="223px" preserveAspectRatio="none" style="width:637px;height:223px;" version="1.1" viewBox="0 0 637 223" width="637px" zoomAndPan="magnify"><defs><filter height="300%" id="fh7abla96c8rb" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[631d54569d64dd7be7afb1602a233020] +entity SphinxProject--><polygon fill="#FEFECE" filter="url(#fh7abla96c8rb)" points="6,30.5,6,66.7969,120,66.7969,120,40.5,110,30.5,6,30.5" style="stroke: #000000; stroke-width: 1.5;"/><path d="M110,30.5 L110,40.5 L120,40.5 " fill="#FEFECE" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="94" x="16" y="53.4951">SphinxProject</text><!--MD5=[61096c0d57626e43fed95496d4441932] +entity .rst--><polygon fill="#FEFECE" filter="url(#fh7abla96c8rb)" points="155,30.5,155,66.7969,197,66.7969,197,40.5,187,30.5,155,30.5" style="stroke: #000000; stroke-width: 1.5;"/><path d="M187,30.5 L187,40.5 L197,40.5 " fill="#FEFECE" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="22" x="165" y="53.4951">.rst</text><!--MD5=[08ed079d9b091f9ed2d220f9f6abc033] +entity .pot--><path d="M359.5,36 C359.5,26 383,26 383,26 C383,26 406.5,26 406.5,36 L406.5,61.2969 C406.5,71.2969 383,71.2969 383,71.2969 C383,71.2969 359.5,71.2969 359.5,61.2969 L359.5,36 " fill="#FEFECE" filter="url(#fh7abla96c8rb)" style="stroke: #000000; stroke-width: 1.5;"/><path d="M359.5,36 C359.5,46 383,46 383,46 C383,46 406.5,46 406.5,36 " fill="none" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="27" x="369.5" y="62.9951">.pot</text><!--MD5=[66eca29884632d3929c321eae20b9288] +entity .po--><path d="M483,36 C483,26 504,26 504,26 C504,26 525,26 525,36 L525,61.2969 C525,71.2969 504,71.2969 504,71.2969 C504,71.2969 483,71.2969 483,61.2969 L483,36 " fill="#FEFECE" filter="url(#fh7abla96c8rb)" style="stroke: #000000; stroke-width: 1.5;"/><path d="M483,36 C483,46 504,46 504,46 C504,46 525,46 525,36 " fill="none" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="22" x="493" y="62.9951">.po</text><!--MD5=[fad5092d1b513ed9e4cd2391fb0fb212] +entity .mo--><path d="M398,176 C398,166 421,166 421,166 C421,166 444,166 444,176 L444,201.2969 C444,211.2969 421,211.2969 421,211.2969 C421,211.2969 398,211.2969 398,201.2969 L398,176 " fill="#FEFECE" filter="url(#fh7abla96c8rb)" style="stroke: #000000; stroke-width: 1.5;"/><path d="M398,176 C398,186 421,186 421,186 C421,186 444,186 444,176 " fill="none" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="26" x="408" y="202.9951">.mo</text><!--MD5=[8f276d451ff344d4b5b89d896332ffcd] +entity translator--><ellipse cx="593" cy="17.5" fill="#FEFECE" filter="url(#fh7abla96c8rb)" rx="8" ry="8" style="stroke: #A80036; stroke-width: 1.5;"/><path d="M593,25.5 L593,52.5 M580,33.5 L606,33.5 M593,52.5 L580,67.5 M593,52.5 L606,67.5 " fill="none" filter="url(#fh7abla96c8rb)" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="65" x="560.5" y="85.9951">translator</text><!--MD5=[ba0f3816bcb6df458d88626e193b44ee] +entity TranslatedBuild--><polygon fill="#FEFECE" filter="url(#fh7abla96c8rb)" points="214.5,170.5,214.5,206.7969,341.5,206.7969,341.5,180.5,331.5,170.5,214.5,170.5" style="stroke: #000000; stroke-width: 1.5;"/><path d="M331.5,170.5 L331.5,180.5 L341.5,180.5 " fill="#FEFECE" style="stroke: #000000; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="107" x="224.5" y="193.4951">TranslatedBuild</text><!--MD5=[2a0f0d8c54238b3eb600ae284aca39d2] +reverse link .po to translator--><path d="M530.44,48.5 C540.43,48.5 550.43,48.5 560.43,48.5 " fill="none" id=".po<-translator" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="525.21,48.5,534.21,52.5,530.21,48.5,534.21,44.5,525.21,48.5" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[25ad71f3d3609323ec521914d1dc498d] +link SphinxProject to .rst--><path d="M120.38,48.5 C130.13,48.5 139.87,48.5 149.61,48.5 " fill="none" id="SphinxProject->.rst" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="154.71,48.5,145.71,44.5,149.71,48.5,145.71,52.5,154.71,48.5" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[1109e8764a7297dc8aca732b1794aa90] +link .rst to .pot--><path d="M197.37,48.5 C234.72,48.5 311.88,48.5 354,48.5 " fill="none" id=".rst->.pot" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="359.21,48.5,350.21,44.5,354.21,48.5,350.21,52.5,359.21,48.5" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="126" x="215.25" y="41.5669">sphinx-build gettext</text><!--MD5=[c2d0ba229470f335ea07ab2ed6b28ec0] +link .pot to .po--><path d="M406.62,48.5 C427.03,48.5 456.51,48.5 477.68,48.5 " fill="none" id=".pot->.po" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="482.87,48.5,473.87,44.5,477.87,48.5,473.87,52.5,482.87,48.5" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="40" x="424.75" y="41.5669">Pootle</text><!--MD5=[06651b5914fbf4764a077bbac7efe19a] +link .po to .mo--><path d="M491.03,71.06 C476.38,95.43 452.52,135.09 436.8,161.24 " fill="none" id=".po->.mo" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="434.15,165.63,442.2104,159.9705,436.7225,161.3425,435.3505,155.8546,434.15,165.63" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="50" x="462" y="132.0669">msgfmt</text><!--MD5=[02fa75427086f2cebad4a5f1b2dd96dd] +reverse link TranslatedBuild to .mo--><path d="M346.94,188.5 C363.88,188.5 380.82,188.5 397.76,188.5 " fill="none" id="TranslatedBuild<-.mo" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="341.68,188.5,350.68,192.5,346.68,188.5,350.68,184.5,341.68,188.5" style="stroke: #A80036; stroke-width: 1.0;"/><!--MD5=[e72b6258a50343d4926d984a36170cf2] +link .rst to TranslatedBuild--><path d="M188.71,66.7 C207.27,91.8 241.75,138.46 262,165.86 " fill="none" id=".rst->TranslatedBuild" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="265.13,170.08,262.9905,160.4663,262.1552,166.0612,256.5604,165.226,265.13,170.08" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="165" x="241" y="132.0669">sphinx-build -Dlanguage=</text><!--MD5=[30dba34f254541587149d90abdb00688] @startuml
file "SphinxProject"
file ".rst"
@@ -13,17 +27,16 @@ SphinxProject -r-> .rst .pot -r-> .po : Pootle
.po -d-> .mo : msgfmt
.mo -l-> TranslatedBuild
-.rst -d-> TranslatedBuild : "sphinx-buid -Dlanguage="
+.rst -d-> TranslatedBuild : "sphinx-build -Dlanguage="
@enduml
-PlantUML version 1.2018.13(Mon Nov 26 18:11:51 CET 2018) +PlantUML version 1.2020.00(Sat Jan 11 12:30:53 GMT 2020) (GPL source distribution) Java Runtime: OpenJDK Runtime Environment JVM: OpenJDK 64-Bit Server VM -Java Version: 11.0.6+10-post-Ubuntu-1ubuntu119.10.1 +Java Version: 1.8.0_252-b09 Operating System: Linux -OS Version: 5.3.0-40-generic Default Encoding: UTF-8 Language: en -Country: US +Country: null --></g></svg>
\ No newline at end of file diff --git a/doc/_themes/sphinx13/static/sphinx13.css b/doc/_themes/sphinx13/static/sphinx13.css index 7c1d46e83..c8fb2e5c9 100644 --- a/doc/_themes/sphinx13/static/sphinx13.css +++ b/doc/_themes/sphinx13/static/sphinx13.css @@ -239,7 +239,7 @@ div.footer a { /* -- body styles ----------------------------------------------------------- */ -p { +p { margin: 0.8em 0 0.5em 0; } diff --git a/doc/conf.py b/doc/conf.py index f62e02a34..9f018bc7b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -4,7 +4,6 @@ import re import sphinx - extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.autosummary', 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx', @@ -15,7 +14,7 @@ templates_path = ['_templates'] exclude_patterns = ['_build'] project = 'Sphinx' -copyright = '2007-2020, Georg Brandl and the Sphinx team' +copyright = '2007-2021, Georg Brandl and the Sphinx team' version = sphinx.__display_version__ release = version show_authors = True @@ -28,6 +27,7 @@ html_sidebars = {'index': ['indexsidebar.html', 'searchbox.html']} html_additional_pages = {'index': 'index.html'} html_use_opensearch = 'https://www.sphinx-doc.org/en/master' html_baseurl = 'https://www.sphinx-doc.org/en/master/' +html_favicon = '_static/favicon.svg' htmlhelp_basename = 'Sphinxdoc' @@ -110,9 +110,10 @@ texinfo_documents = [ 1), ] -# We're not using intersphinx right now, but if we did, this would be part of -# the mapping: -intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)} +intersphinx_mapping = { + 'python': ('https://docs.python.org/3/', None), + 'requests': ('https://requests.readthedocs.io/en/master', None), +} # Sphinx document translation with sphinx gettext feature uses these settings: locale_dirs = ['locale/'] diff --git a/doc/contents.rst b/doc/contents.rst index 17a3d4b54..eb6946292 100644 --- a/doc/contents.rst +++ b/doc/contents.rst @@ -10,7 +10,6 @@ Sphinx documentation contents development/index man/index - theming templating latex extdev/index diff --git a/doc/development/builders.rst b/doc/development/builders.rst new file mode 100644 index 000000000..bb6777023 --- /dev/null +++ b/doc/development/builders.rst @@ -0,0 +1,34 @@ +Configuring builders +==================== + +Discover builders by entry point +-------------------------------- + +.. versionadded:: 1.6 + +:term:`builder` extensions can be discovered by means of `entry points`_ so +that they do not have to be listed in the :confval:`extensions` configuration +value. + +Builder extensions should define an entry point in the ``sphinx.builders`` +group. The name of the entry point needs to match your builder's +:attr:`~.Builder.name` attribute, which is the name passed to the +:option:`sphinx-build -b` option. The entry point value should equal the +dotted name of the extension module. Here is an example of how an entry point +for 'mybuilder' can be defined in the extension's ``setup.py`` + +.. code-block:: python + + setup( + # ... + entry_points={ + 'sphinx.builders': [ + 'mybuilder = my.extension.module', + ], + } + ) + +Note that it is still necessary to register the builder using +:meth:`~.Sphinx.add_builder` in the extension's :func:`setup` function. + +.. _entry points: https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins diff --git a/doc/development/index.rst b/doc/development/index.rst index 6a3406a20..b4a7920ba 100644 --- a/doc/development/index.rst +++ b/doc/development/index.rst @@ -2,12 +2,22 @@ Extending Sphinx ================ -This guide is aimed at those wishing to develop their own extensions for -Sphinx. Sphinx possesses significant extensibility capabilities including the -ability to hook into almost every point of the build process. If you simply -wish to use Sphinx with existing extensions, refer to :doc:`/usage/index`. +This guide is aimed at giving a quick introduction for those wishing to +develop their own extensions for Sphinx. Sphinx possesses significant +extensibility capabilities including the ability to hook into almost every +point of the build process. If you simply wish to use Sphinx with existing +extensions, refer to :doc:`/usage/index`. For a more detailed discussion of +the extension interface see :doc:`/extdev/index`. .. toctree:: :maxdepth: 2 + overview tutorials/index + builders + +.. toctree:: + :caption: Theming + :maxdepth: 2 + + theming diff --git a/doc/development/overview.rst b/doc/development/overview.rst new file mode 100644 index 000000000..ad474999a --- /dev/null +++ b/doc/development/overview.rst @@ -0,0 +1,32 @@ +Developing extensions overview +============================== + +This page contains general information about developing Sphinx extensions. + +Make an extension depend on another extension +--------------------------------------------- + +Sometimes your extension depends on the functionality of another +Sphinx extension. Most Sphinx extensions are activated in a +project's :file:`conf.py` file, but this is not available to you as an +extension developer. + +.. module:: sphinx.application + :noindex: + +To ensure that another extension is activated as a part of your own extension, +use the :meth:`Sphinx.setup_extension` method. This will +activate another extension at run-time, ensuring that you have access to its +functionality. + +For example, the following code activates the ``recommonmark`` extension: + +.. code-block:: python + + def setup(app): + app.setup_extension("recommonmark") + +.. note:: + + Since your extension will depend on another, make sure to include + it as a part of your extension's installation requirements. diff --git a/doc/development/theming.rst b/doc/development/theming.rst new file mode 100644 index 000000000..5de10158a --- /dev/null +++ b/doc/development/theming.rst @@ -0,0 +1,336 @@ +HTML theme development +====================== + +.. versionadded:: 0.6 + +.. note:: + + This document provides information about creating your own theme. If you + simply wish to use a pre-existing HTML themes, refer to + :doc:`/usage/theming`. + +Sphinx supports changing the appearance of its HTML output via *themes*. A +theme is a collection of HTML templates, stylesheet(s) and other static files. +Additionally, it has a configuration file which specifies from which theme to +inherit, which highlighting style to use, and what options exist for customizing +the theme's look and feel. + +Themes are meant to be project-unaware, so they can be used for different +projects without change. + +.. note:: + + See :ref:`dev-extensions` for more information that may + be helpful in developing themes. + + +Creating themes +--------------- + +Themes take the form of either a directory or a zipfile (whose name is the +theme name), containing the following: + +* A :file:`theme.conf` file. +* HTML templates, if needed. +* A ``static/`` directory containing any static files that will be copied to the + output static directory on build. These can be images, styles, script files. + +The :file:`theme.conf` file is in INI format [1]_ (readable by the standard +Python :mod:`ConfigParser` module) and has the following structure: + +.. sourcecode:: ini + + [theme] + inherit = base theme + stylesheet = main CSS name + pygments_style = stylename + sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html + + [options] + variable = default value + +* The **inherit** setting gives the name of a "base theme", or ``none``. The + base theme will be used to locate missing templates (most themes will not have + to supply most templates if they use ``basic`` as the base theme), its options + will be inherited, and all of its static files will be used as well. If you + want to also inherit the stylesheet, include it via CSS' ``@import`` in your + own. + +* The **stylesheet** setting gives the name of a CSS file which will be + referenced in the HTML header. If you need more than one CSS file, either + include one from the other via CSS' ``@import``, or use a custom HTML template + that adds ``<link rel="stylesheet">`` tags as necessary. Setting the + :confval:`html_style` config value will override this setting. + +* The **pygments_style** setting gives the name of a Pygments style to use for + highlighting. This can be overridden by the user in the + :confval:`pygments_style` config value. + +* The **pygments_dark_style** setting gives the name of a Pygments style to use + for highlighting when the CSS media query ``(prefers-color-scheme: dark)`` + evaluates to true. It is injected into the page using + :meth:`~Sphinx.add_css_file()`. + +* The **sidebars** setting gives the comma separated list of sidebar templates + for constructing sidebars. This can be overridden by the user in the + :confval:`html_sidebars` config value. + +* The **options** section contains pairs of variable names and default values. + These options can be overridden by the user in :confval:`html_theme_options` + and are accessible from all templates as ``theme_<name>``. + +.. versionadded:: 1.7 + sidebar settings + + +.. _distribute-your-theme: + +Distribute your theme as a Python package +----------------------------------------- + +As a way to distribute your theme, you can use Python package. Python package +brings to users easy setting up ways. + +To distribute your theme as a Python package, please define an entry point +called ``sphinx.html_themes`` in your ``setup.py`` file, and write a ``setup()`` +function to register your themes using ``add_html_theme()`` API in it:: + + # 'setup.py' + setup( + ... + entry_points = { + 'sphinx.html_themes': [ + 'name_of_theme = your_package', + ] + }, + ... + ) + + # 'your_package.py' + from os import path + + def setup(app): + app.add_html_theme('name_of_theme', path.abspath(path.dirname(__file__))) + +If your theme package contains two or more themes, please call +``add_html_theme()`` twice or more. + +.. versionadded:: 1.2 + 'sphinx_themes' entry_points feature. + +.. deprecated:: 1.6 + ``sphinx_themes`` entry_points has been deprecated. + +.. versionadded:: 1.6 + ``sphinx.html_themes`` entry_points feature. + + +Templating +---------- + +The :doc:`guide to templating </templating>` is helpful if you want to write your +own templates. What is important to keep in mind is the order in which Sphinx +searches for templates: + +* First, in the user's ``templates_path`` directories. +* Then, in the selected theme. +* Then, in its base theme, its base's base theme, etc. + +When extending a template in the base theme with the same name, use the theme +name as an explicit directory: ``{% extends "basic/layout.html" %}``. From a +user ``templates_path`` template, you can still use the "exclamation mark" +syntax as described in the templating document. + + +.. _theming-static-templates: + +Static templates +~~~~~~~~~~~~~~~~ + +Since theme options are meant for the user to configure a theme more easily, +without having to write a custom stylesheet, it is necessary to be able to +template static files as well as HTML files. Therefore, Sphinx supports +so-called "static templates", like this: + +If the name of a file in the ``static/`` directory of a theme (or in the user's +static path, for that matter) ends with ``_t``, it will be processed by the +template engine. The ``_t`` will be left from the final file name. For +example, the *classic* theme has a file ``static/classic.css_t`` which uses +templating to put the color options into the stylesheet. When a documentation +is built with the classic theme, the output directory will contain a +``_static/classic.css`` file where all template tags have been processed. + + +Use custom page metadata in HTML templates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Any key / value pairs in :doc:`field lists </usage/restructuredtext/field-lists>` +that are placed *before* the page's title will be available to the Jinja +template when building the page within the :data:`meta` attribute. For example, +if a page had the following text before its first title: + +.. code-block:: rst + + :mykey: My value + + My first title + -------------- + +Then it could be accessed within a Jinja template like so: + +.. code-block:: jinja + + {%- if meta is mapping %} + {{ meta.get("mykey") }} + {%- endif %} + +Note the check that ``meta`` is a dictionary ("mapping" in Jinja +terminology) to ensure that using it in this way is valid. + + +Defining custom template functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes it is useful to define your own function in Python that you wish to +then use in a template. For example, if you'd like to insert a template value +with logic that depends on the user's configuration in the project, or if you'd +like to include non-trivial checks and provide friendly error messages for +incorrect configuration in the template. + +To define your own template function, you'll need to define two functions +inside your module: + +* A **page context event handler** (or **registration**) function. This is + connected to the :class:`.Sphinx` application via an event callback. +* A **template function** that you will use in your Jinja template. + +First, define the registration function, which accepts the arguments for +:event:`html-page-context`. + +Within the registration function, define the template function that you'd like to use +within Jinja. The template function should return a string or Python objects (lists, +dictionaries) with strings inside that Jinja uses in the templating process + +.. note:: + + The template function will have access to all of the variables that + are passed to the registration function. + +At the end of the registration function, add the template function to the +Sphinx application's context with ``context['template_func'] = template_func``. + +Finally, in your extension's ``setup()`` function, add your registration +function as a callback for :event:`html-page-context`. + +.. code-block:: python + + # The registration function + def setup_my_func(app, pagename, templatename, context, doctree): + # The template function + def my_func(mystring): + return "Your string is %s" % mystring + # Add it to the page's context + context['my_func'] = my_func + + # Your extension's setup function + def setup(app): + app.connect("html-page-context", setup_my_func) + +Now, you will have access to this function in jinja like so: + +.. code-block:: jinja + + <div> + {{ my_func("some string") }} + </div> + + +Add your own static files to the build assets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are packaging your own build assets with an extension +(e.g., a CSS or JavaScript file), you need to ensure that they are placed +in the ``_static/`` folder of HTML outputs. To do so, you may copy them directly +into a build's ``_static/`` folder at build time, generally via an event hook. +Here is some sample code to accomplish this: + +.. code-block:: python + + def copy_custom_files(app, exc): + if app.builder.format == 'html' and not exc: + staticdir = path.join(app.builder.outdir, '_static') + copy_asset_file('path/to/myextension/_static/myjsfile.js', staticdir) + + def setup(app): + app.connect('builder-inited', copy_custom_files) + + +Inject JavaScript based on user configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your extension makes use of JavaScript, it can be useful to allow users +to control its behavior using their Sphinx configuration. However, this can +be difficult to do if your JavaScript comes in the form of a static library +(which will not be built with Jinja). + +There are two ways to inject variables into the JavaScript space based on user +configuration. + +First, you may append ``_t`` to the end of any static files included with your +extension. This will cause Sphinx to process these files with the templating +engine, allowing you to embed variables and control behavior. + +For example, the following JavaScript structure: + +.. code-block:: bash + + mymodule/ + ├── _static + │ └── myjsfile.js_t + └── mymodule.py + +Will result in the following static file placed in your HTML's build output: + +.. code-block:: bash + + _build/ + └── html + └── _static + └── myjsfile.js + +See :ref:`theming-static-templates` for more information. + +Second, you may use the :meth:`Sphinx.add_js_file` method without pointing it +to a file. Normally, this method is used to insert a new JavaScript file +into your site. However, if you do *not* pass a file path, but instead pass +a string to the "body" argument, then this text will be inserted as JavaScript +into your site's head. This allows you to insert variables into your project's +JavaScript from Python. + +For example, the following code will read in a user-configured value and then +insert this value as a JavaScript variable, which your extension's JavaScript +code may use: + +.. code-block:: python + + # This function reads in a variable and inserts it into JavaScript + def add_js_variable(app): + # This is a configuration that you've specified for users in `conf.py` + js_variable = app.config['my_javascript_variable'] + js_text = "var my_variable = '%s';" % js_variable + app.add_js_file(None, body=js_text) + # We connect this function to the step after the builder is initialized + def setup(app): + # Tell Sphinx about this configuration variable + app.add_config_value('my_javascript_variable') + # Run the function after the builder is initialized + app.connect('builder-inited', add_js_variable) + +As a result, in your theme you can use code that depends on the presence of +this variable. Users can control the variable's value by defining it in their +:file:`conf.py` file. + + +.. [1] It is not an executable Python file, as opposed to :file:`conf.py`, + because that would pose an unnecessary security risk if themes are + shared. diff --git a/doc/development/tutorials/examples/recipe.py b/doc/development/tutorials/examples/recipe.py index 2464302da..c7317578b 100644 --- a/doc/development/tutorials/examples/recipe.py +++ b/doc/development/tutorials/examples/recipe.py @@ -4,8 +4,7 @@ from docutils.parsers.rst import directives from sphinx import addnodes from sphinx.directives import ObjectDescription -from sphinx.domains import Domain -from sphinx.domains import Index +from sphinx.domains import Domain, Index from sphinx.roles import XRefRole from sphinx.util.nodes import make_refnode diff --git a/doc/development/tutorials/examples/todo.py b/doc/development/tutorials/examples/todo.py index 7eee534d0..59e394ee8 100644 --- a/doc/development/tutorials/examples/todo.py +++ b/doc/development/tutorials/examples/todo.py @@ -61,6 +61,13 @@ def purge_todos(app, env, docname): if todo['docname'] != docname] +def merge_todos(app, env, docnames, other): + if not hasattr(env, 'todo_all_todos'): + env.todo_all_todos = [] + if hasattr(other, 'todo_all_todos'): + env.todo_all_todos.extend(other.todo_all_todos) + + def process_todo_nodes(app, doctree, fromdocname): if not app.config.todo_include_todos: for node in doctree.traverse(todo): @@ -119,6 +126,7 @@ def setup(app): app.add_directive('todolist', TodolistDirective) app.connect('doctree-resolved', process_todo_nodes) app.connect('env-purge-doc', purge_todos) + app.connect('env-merge-info', merge_todos) return { 'version': '0.1', diff --git a/doc/development/tutorials/index.rst b/doc/development/tutorials/index.rst index a79e6a8b6..be126b3ca 100644 --- a/doc/development/tutorials/index.rst +++ b/doc/development/tutorials/index.rst @@ -1,8 +1,11 @@ +.. _extension-tutorials-index: + Extension tutorials =================== Refer to the following tutorials to get started with extension development. + .. toctree:: :caption: Directive tutorials :maxdepth: 1 diff --git a/doc/development/tutorials/todo.rst b/doc/development/tutorials/todo.rst index e27528b5a..21d9e74be 100644 --- a/doc/development/tutorials/todo.rst +++ b/doc/development/tutorials/todo.rst @@ -38,9 +38,10 @@ For that, we will need to add the following elements to Sphinx: with the extension name, in order to stay unique) that controls whether todo entries make it into the output. -* New event handlers: one for the :event:`doctree-resolved` event, to replace - the todo and todolist nodes, and one for :event:`env-purge-doc` (the reason - for that will be covered later). +* New event handlers: one for the :event:`doctree-resolved` event, to + replace the todo and todolist nodes, one for :event:`env-merge-info` + to merge intermediate results from parallel builds, and one for + :event:`env-purge-doc` (the reason for that will be covered later). Prerequisites @@ -212,12 +213,23 @@ Here we clear out all todos whose docname matches the given one from the ``todo_all_todos`` list. If there are todos left in the document, they will be added again during parsing. +The next handler, for the :event:`env-merge-info` event, is used +during parallel builds. As during parallel builds all threads have +their own ``env``, there's multiple ``todo_all_todos`` lists that need +to be merged: + +.. literalinclude:: examples/todo.py + :language: python + :linenos: + :lines: 64-68 + + The other handler belongs to the :event:`doctree-resolved` event: .. literalinclude:: examples/todo.py :language: python :linenos: - :lines: 64-103 + :lines: 71-113 The :event:`doctree-resolved` event is emitted at the end of :ref:`phase 3 (resolving) <build-phases>` and allows custom resolving to be done. The handler @@ -230,7 +242,7 @@ where they come from. The list items are composed of the nodes from the ``todo`` entry and docutils nodes created on the fly: a paragraph for each entry, containing text that gives the location, and a link (reference node containing an italic node) with the backreference. The reference URI is built -by :meth:`sphinx.builders.Builder.get_relative_uri`` which creates a suitable +by :meth:`sphinx.builders.Builder.get_relative_uri` which creates a suitable URI depending on the used builder, and appending the todo node's (the target's) ID as the anchor name. @@ -245,7 +257,7 @@ the other parts of our extension. Let's look at our ``setup`` function: .. literalinclude:: examples/todo.py :language: python :linenos: - :lines: 106- + :lines: 116- The calls in this function refer to the classes and functions we added earlier. What the individual calls do is the following: diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst index d5b1a8a98..4585df949 100644 --- a/doc/extdev/appapi.rst +++ b/doc/extdev/appapi.rst @@ -25,75 +25,75 @@ package. .. currentmodule:: sphinx.application -.. automethod:: Sphinx.setup_extension(name) +.. automethod:: Sphinx.setup_extension -.. automethod:: Sphinx.require_sphinx(version) +.. automethod:: Sphinx.require_sphinx -.. automethod:: Sphinx.connect(event, callback) +.. automethod:: Sphinx.connect -.. automethod:: Sphinx.disconnect(listener_id) +.. automethod:: Sphinx.disconnect -.. automethod:: Sphinx.add_builder(builder) +.. automethod:: Sphinx.add_builder -.. automethod:: Sphinx.add_config_value(name, default, rebuild) +.. automethod:: Sphinx.add_config_value -.. automethod:: Sphinx.add_event(name) +.. automethod:: Sphinx.add_event -.. automethod:: Sphinx.set_translator(name, translator_class) +.. automethod:: Sphinx.set_translator -.. automethod:: Sphinx.add_node(node, \*\*kwds) +.. automethod:: Sphinx.add_node -.. automethod:: Sphinx.add_enumerable_node(node, figtype, title_getter=None, \*\*kwds) +.. automethod:: Sphinx.add_enumerable_node -.. automethod:: Sphinx.add_directive(name, directiveclass) +.. automethod:: Sphinx.add_directive -.. automethod:: Sphinx.add_role(name, role) +.. automethod:: Sphinx.add_role -.. automethod:: Sphinx.add_generic_role(name, nodeclass) +.. automethod:: Sphinx.add_generic_role -.. automethod:: Sphinx.add_domain(domain) +.. automethod:: Sphinx.add_domain -.. automethod:: Sphinx.add_directive_to_domain(domain, name, directiveclass) +.. automethod:: Sphinx.add_directive_to_domain -.. automethod:: Sphinx.add_role_to_domain(domain, name, role) +.. automethod:: Sphinx.add_role_to_domain -.. automethod:: Sphinx.add_index_to_domain(domain, index) +.. automethod:: Sphinx.add_index_to_domain -.. automethod:: Sphinx.add_object_type(directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None, objname='', doc_field_types=[]) +.. automethod:: Sphinx.add_object_type -.. automethod:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None, objname='') +.. automethod:: Sphinx.add_crossref_type -.. automethod:: Sphinx.add_transform(transform) +.. automethod:: Sphinx.add_transform -.. automethod:: Sphinx.add_post_transform(transform) +.. automethod:: Sphinx.add_post_transform -.. automethod:: Sphinx.add_js_file(filename, **kwargs) +.. automethod:: Sphinx.add_js_file -.. automethod:: Sphinx.add_css_file(filename, **kwargs) +.. automethod:: Sphinx.add_css_file -.. automethod:: Sphinx.add_latex_package(packagename, options=None) +.. automethod:: Sphinx.add_latex_package -.. automethod:: Sphinx.add_lexer(alias, lexer) +.. automethod:: Sphinx.add_lexer -.. automethod:: Sphinx.add_autodocumenter(cls) +.. automethod:: Sphinx.add_autodocumenter -.. automethod:: Sphinx.add_autodoc_attrgetter(type, getter) +.. automethod:: Sphinx.add_autodoc_attrgetter -.. automethod:: Sphinx.add_search_language(cls) +.. automethod:: Sphinx.add_search_language -.. automethod:: Sphinx.add_source_suffix(suffix, filetype) +.. automethod:: Sphinx.add_source_suffix -.. automethod:: Sphinx.add_source_parser(parser) +.. automethod:: Sphinx.add_source_parser -.. automethod:: Sphinx.add_env_collector(collector) +.. automethod:: Sphinx.add_env_collector -.. automethod:: Sphinx.add_html_theme(name, theme_path) +.. automethod:: Sphinx.add_html_theme -.. automethod:: Sphinx.add_html_math_renderer(name, inline_renderers, block_renderers) +.. automethod:: Sphinx.add_html_math_renderer -.. automethod:: Sphinx.add_message_catalog(catalog, locale_dir) +.. automethod:: Sphinx.add_message_catalog -.. automethod:: Sphinx.is_parallel_allowed(typ) +.. automethod:: Sphinx.is_parallel_allowed .. exception:: ExtensionError @@ -107,9 +107,9 @@ Emitting events .. class:: Sphinx :noindex: - .. automethod:: emit(event, \*arguments) + .. automethod:: emit - .. automethod:: emit_firstresult(event, \*arguments) + .. automethod:: emit_firstresult Sphinx runtime information @@ -157,6 +157,42 @@ connect handlers to the events. Example: app.connect('source-read', source_read_handler) +Below is an overview of each event that happens during a build. In the list +below, we include the event name, its callback parameters, and the input and output +type for that event:: + + 1. event.config-inited(app,config) + 2. event.builder-inited(app) + 3. event.env-get-outdated(app, env, added, changed, removed) + 4. event.env-before-read-docs(app, env, docnames) + + for docname in docnames: + 5. event.env-purge-doc(app, env, docname) + if doc changed and not removed: + 6. source-read(app, docname, source) + 7. run source parsers: text -> docutils.document (parsers can be added with the app.add_source_parser() API) + 8. apply transforms (by priority): docutils.document -> docutils.document + - event.doctree-read(app, doctree) is called in the middly of transforms, + transforms come before/after this event depending on their priority. + 9. (if running in parallel mode, for each process) event.env-merged-info(app, env, docnames, other) + 10. event.env-updated(app, env) + 11. event.env-get-updated(app, env) + 12. event.env-check-consistency(app, env) + + # The updated-docs list can be builder dependent, but generally includes all new/changed documents, + # plus any output from `env-get-updated`, and then all "parent" documents in the ToC tree + # For builders that output a single page, they are first joined into a single doctree before post-transforms/doctree-resolved + for docname in updated-docs: + 13. apply post-transforms (by priority): docutils.document -> docutils.document + 14. event.doctree-resolved(app, doctree, docname) + - (for any reference node that fails to resolve) event.missing-reference(env, node, contnode) + - (for any reference node that fails to resolve) event.warn-missing-reference(domain, node) + + 15. Generate output files + 16. event.build-finished(app, exception) + +Here is a more detailed list of these events. + .. event:: builder-inited (app) Emitted when the builder object has been created. It is available as @@ -249,6 +285,14 @@ connect handlers to the events. Example: .. versionadded:: 0.5 +.. event:: warn-missing-reference (app, domain, node) + + Emitted when a cross-reference to an object cannot be resolved even after + :event:`missing-reference`. If the event handler can emit warnings for + the missing reference, it should return ``True``. + + .. versionadded:: 3.4 + .. event:: doctree-resolved (app, doctree, docname) Emitted when a doctree has been "resolved" by the environment, that is, all @@ -325,6 +369,9 @@ connect handlers to the events. Example: You can return a string from the handler, it will then replace ``'page.html'`` as the HTML template for this page. + .. note:: You can install JS/CSS files for the specific page via + :meth:`Sphinx.add_js_file` and :meth:`Sphinx.add_css_file` since v3.5.0. + .. versionadded:: 0.4 .. versionchanged:: 1.3 diff --git a/doc/extdev/deprecated.rst b/doc/extdev/deprecated.rst index 7e59184ec..dc9d9973d 100644 --- a/doc/extdev/deprecated.rst +++ b/doc/extdev/deprecated.rst @@ -26,6 +26,167 @@ The following is a list of deprecated interfaces. - (will be) Removed - Alternatives + * - pending_xref node for viewcode extension + - 3.5 + - 5.0 + - ``sphinx.ext.viewcode.viewcode_anchor`` + + * - ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.broken`` + - 3.5 + - 5.0 + - N/A + + * - ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.good`` + - 3.5 + - 5.0 + - N/A + + * - ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.redirected`` + - 3.5 + - 5.0 + - N/A + + * - ``sphinx.builders.linkcheck.node_line_or_0()`` + - 3.5 + - 5.0 + - ``sphinx.util.nodes.get_node_line()`` + + * - ``sphinx.ext.autodoc.AttributeDocumenter.isinstanceattribute()`` + - 3.5 + - 5.0 + - N/A + + * - ``sphinx.ext.autodoc.importer.get_module_members()`` + - 3.5 + - 5.0 + - ``sphinx.ext.autodoc.ModuleDocumenter.get_module_members()`` + + * - ``sphinx.ext.autosummary.generate._simple_info()`` + - 3.5 + - 5.0 + - :ref:`logging-api` + + * - ``sphinx.ext.autosummary.generate._simple_warn()`` + - 3.5 + - 5.0 + - :ref:`logging-api` + + * - ``sphinx.writers.html.HTMLTranslator.permalink_text`` + - 3.5 + - 5.0 + - :confval:`html_permalinks_icon` + + * - ``sphinx.writers.html5.HTML5Translator.permalink_text`` + - 3.5 + - 5.0 + - :confval:`html_permalinks_icon` + + * - The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()`` + - 3.4 + - 5.0 + - N/A + + * - The ``no_docstring`` argument of + ``sphinx.ext.autodoc.Documenter.add_content()`` + - 3.4 + - 5.0 + - ``sphinx.ext.autodoc.Documenter.get_doc()`` + + * - ``sphinx.ext.autodoc.Documenter.get_object_members()`` + - 3.4 + - 6.0 + - ``sphinx.ext.autodoc.ClassDocumenter.get_object_members()`` + + * - ``sphinx.ext.autodoc.DataDeclarationDocumenter`` + - 3.4 + - 5.0 + - ``sphinx.ext.autodoc.DataDocumenter`` + + * - ``sphinx.ext.autodoc.GenericAliasDocumenter`` + - 3.4 + - 5.0 + - ``sphinx.ext.autodoc.DataDocumenter`` + + * - ``sphinx.ext.autodoc.InstanceAttributeDocumenter`` + - 3.4 + - 5.0 + - ``sphinx.ext.autodoc.AttributeDocumenter`` + + * - ``sphinx.ext.autodoc.SlotsAttributeDocumenter`` + - 3.4 + - 5.0 + - ``sphinx.ext.autodoc.AttributeDocumenter`` + + * - ``sphinx.ext.autodoc.TypeVarDocumenter`` + - 3.4 + - 5.0 + - ``sphinx.ext.autodoc.DataDocumenter`` + + * - ``sphinx.ext.autodoc.directive.DocumenterBridge.reporter`` + - 3.5 + - 5.0 + - ``sphinx.util.logging`` + + * - ``sphinx.ext.autodoc.importer._getannotations()`` + - 3.4 + - 4.0 + - ``sphinx.util.inspect.getannotations()`` + + * - ``sphinx.ext.autodoc.importer._getmro()`` + - 3.4 + - 4.0 + - ``sphinx.util.inspect.getmro()`` + + * - ``sphinx.pycode.ModuleAnalyzer.parse()`` + - 3.4 + - 5.0 + - ``sphinx.pycode.ModuleAnalyzer.analyze()`` + + * - ``sphinx.util.osutil.movefile()`` + - 3.4 + - 5.0 + - ``os.replace()`` + + * - ``sphinx.util.requests.is_ssl_error()`` + - 3.4 + - 5.0 + - N/A + + * - ``sphinx.builders.latex.LaTeXBuilder.usepackages`` + - 3.3 + - 5.0 + - N/A + + * - ``sphinx.builders.latex.LaTeXBuilder.usepackages_afger_hyperref`` + - 3.3 + - 5.0 + - N/A + + * - ``sphinx.ext.autodoc.SingledispatchFunctionDocumenter`` + - 3.3 + - 5.0 + - ``sphinx.ext.autodoc.FunctionDocumenter`` + + * - ``sphinx.ext.autodoc.SingledispatchMethodDocumenter`` + - 3.3 + - 5.0 + - ``sphinx.ext.autodoc.MethodDocumenter`` + + * - ``sphinx.ext.autodoc.members_set_option()`` + - 3.2 + - 5.0 + - N/A + + * - ``sphinx.ext.autodoc.merge_special_members_option()`` + - 3.2 + - 5.0 + - ``sphinx.ext.autodoc.merge_members_option()`` + + * - ``sphinx.writers.texinfo.TexinfoWriter.desc`` + - 3.2 + - 5.0 + - ``sphinx.writers.texinfo.TexinfoWriter.descs`` + * - The first argument for ``sphinx.ext.autosummary.generate.AutosummaryRenderer`` has been changed to Sphinx object diff --git a/doc/extdev/domainapi.rst b/doc/extdev/domainapi.rst index d6ecf0633..674a3aa9a 100644 --- a/doc/extdev/domainapi.rst +++ b/doc/extdev/domainapi.rst @@ -1,7 +1,7 @@ .. _domain-api: Domain API ----------- +========== .. module:: sphinx.domains @@ -12,3 +12,16 @@ Domain API .. autoclass:: Index :members: + + +Python Domain +------------- + +.. module:: sphinx.domains.python + +.. autoclass:: PythonDomain + + .. autoattribute:: objects + .. autoattribute:: modules + .. automethod:: note_object + .. automethod:: note_module diff --git a/doc/extdev/index.rst b/doc/extdev/index.rst index 266da52b7..ad04951f3 100644 --- a/doc/extdev/index.rst +++ b/doc/extdev/index.rst @@ -3,54 +3,41 @@ Developing extensions for Sphinx ================================ -Since many projects will need special features in their documentation, Sphinx is -designed to be extensible on several levels. - -This is what you can do in an extension: First, you can add new -:term:`builder`\s to support new output formats or actions on the parsed -documents. Then, it is possible to register custom reStructuredText roles and -directives, extending the markup. And finally, there are so-called "hook -points" at strategic places throughout the build process, where an extension can -register a hook and run specialized code. - -An extension is simply a Python module. When an extension is loaded, Sphinx -imports this module and executes its ``setup()`` function, which in turn -notifies Sphinx of everything the extension offers -- see the extension tutorial -for examples. - -The configuration file itself can be treated as an extension if it contains a -``setup()`` function. All other extensions to load must be listed in the -:confval:`extensions` configuration value. - -Discovery of builders by entry point ------------------------------------- - -.. versionadded:: 1.6 - -:term:`builder` extensions can be discovered by means of `entry points`_ so -that they do not have to be listed in the :confval:`extensions` configuration -value. - -Builder extensions should define an entry point in the ``sphinx.builders`` -group. The name of the entry point needs to match your builder's -:attr:`~.Builder.name` attribute, which is the name passed to the -:option:`sphinx-build -b` option. The entry point value should equal the -dotted name of the extension module. Here is an example of how an entry point -for 'mybuilder' can be defined in the extension's ``setup.py``:: - - setup( - # ... - entry_points={ - 'sphinx.builders': [ - 'mybuilder = my.extension.module', - ], - } - ) - -Note that it is still necessary to register the builder using -:meth:`~.Sphinx.add_builder` in the extension's :func:`setup` function. - -.. _entry points: https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins +Since many projects will need special features in their documentation, Sphinx +is designed to be extensible on several levels. + +Here are a few things you can do in an extension: + +* Add new :term:`builder`\s to support new output formats or actions on the + parsed documents. +* Register custom reStructuredText roles and directives, extending the markup + using the :doc:`markupapi`. +* Add custom code to so-called "hook points" at strategic places throughout the + build process, allowing you to register a hook and run specialized code. + For example, see the :ref:`events`. + +An extension is simply a Python module with a ``setup()`` function. A user +activates the extension by placing the extension's module name +(or a sub-module) in their :confval:`extensions` configuration value. + +When :program:`sphinx-build` is executed, Sphinx will attempt to import each +module that is listed, and execute ``yourmodule.setup(app)``. This +function is used to prepare the extension (e.g., by executing Python code), +linking resources that Sphinx uses in the build process (like CSS or HTML +files), and notifying Sphinx of everything the extension offers (such +as directive or role definitions). The ``app`` argument is an instance of +:class:`.Sphinx` and gives you control over most aspects of the Sphinx build. + +.. note:: + + The configuration file itself can be treated as an extension if it + contains a ``setup()`` function. All other extensions to load must be + listed in the :confval:`extensions` configuration value. + +The rest of this page describes some high-level aspects of developing +extensions and various parts of Sphinx's behavior that you can control. +For some examples of how extensions can be built and used to control different +parts of Sphinx, see the :ref:`extension-tutorials-index`. .. _important-objects: @@ -192,6 +179,11 @@ as metadata of the extension. Metadata keys currently recognized are: APIs used for writing extensions -------------------------------- +These sections provide a more complete description of the tools at your +disposal when developing Sphinx extensions. Some are core to Sphinx +(such as the :doc:`appapi`) while others trigger specific behavior +(such as the :doc:`i18n`) + .. toctree:: :maxdepth: 2 diff --git a/doc/glossary.rst b/doc/glossary.rst index d3367e5df..87b7014b6 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -9,8 +9,8 @@ Glossary A class (inheriting from :class:`~sphinx.builders.Builder`) that takes parsed documents and performs an action on them. Normally, builders translate the documents to an output format, but it is also possible to - use the builder builders that e.g. check for broken links in the - documentation, or build coverage information. + use builders that e.g. check for broken links in the documentation, or + build coverage information. See :doc:`/usage/builders/index` for an overview over Sphinx's built-in builders. diff --git a/doc/internals/contributing.rst b/doc/internals/contributing.rst index 0e464478a..798736b03 100644 --- a/doc/internals/contributing.rst +++ b/doc/internals/contributing.rst @@ -12,6 +12,9 @@ Getting help The Sphinx community maintains a number of mailing lists and IRC channels. +Stack Overflow with tag `python-sphinx`_ + Questions and answers about use and development. + sphinx-users <sphinx-users@googlegroups.com> Mailing list for user support. @@ -21,6 +24,7 @@ sphinx-dev <sphinx-dev@googlegroups.com> #sphinx-doc on irc.freenode.net IRC channel for development questions and user support. +.. _python-sphinx: https://stackoverflow.com/questions/tagged/python-sphinx Bug Reports and Feature Requests -------------------------------- @@ -134,10 +138,7 @@ Coding style Please follow these guidelines when writing code for Sphinx: -* Try to use the same code style as used in the rest of the project. See the - `Pocoo Styleguide`__ for more information. - - __ http://flask.pocoo.org/docs/styleguide/ +* Try to use the same code style as used in the rest of the project. * For non-trivial changes, please update the :file:`CHANGES` file. If your changes alter existing behavior, please document this. @@ -268,9 +269,9 @@ identifier and put ``sphinx.po`` in there. Don't forget to update the possible values for :confval:`language` in ``doc/usage/configuration.rst``. The Sphinx core messages can also be translated on `Transifex -<https://www.transifex.com/sphinx-doc/>`_. There ``tx`` client tool, which is -provided by the ``transifex_client`` Python package, can be used to pull -translations in ``.po`` format from Transifex. To do this, go to +<https://www.transifex.com/sphinx-doc/sphinx-1/>`_. There ``tx`` client tool, +which is provided by the ``transifex_client`` Python package, can be used to +pull translations in ``.po`` format from Transifex. To do this, go to ``sphinx/locale`` and then run ``tx pull -f -l LANG`` where ``LANG`` is an existing language identifier. It is good practice to run ``python setup.py update_catalog`` afterwards to make sure the ``.po`` file has the canonical diff --git a/doc/latex.rst b/doc/latex.rst index 53fe9301a..77d58389f 100644 --- a/doc/latex.rst +++ b/doc/latex.rst @@ -95,6 +95,12 @@ Keys that you may want to override include: A string which will be positioned early in the preamble, designed to contain ``\\PassOptionsToPackage{options}{foo}`` commands. + .. hint:: + + It may be also used for loading LaTeX packages very early in the + preamble. For example package ``fancybox`` is incompatible with + being loaded via the ``'preamble'`` key, it must be loaded earlier. + Default: ``''`` .. versionadded:: 1.4 @@ -195,8 +201,8 @@ Keys that you may want to override include: "Bjornstrup". You can also set this to ``''`` to disable fncychap. Default: ``'\\usepackage[Bjarne]{fncychap}'`` for English documents, - ``'\\usepackage[Sonny]{fncychap}'`` for internationalized documents, and - ``''`` for Japanese documents. + ``'\\usepackage[Sonny]{fncychap}'`` for internationalized documents, and + ``''`` for Japanese documents. ``'preamble'`` Additional preamble content. One may move all needed macros into some file @@ -300,7 +306,7 @@ Keys that don't need to be overridden unless in special cases are: "inputenc" package inclusion. Default: ``'\\usepackage[utf8]{inputenc}'`` when using pdflatex, else - ``''`` + ``''`` .. versionchanged:: 1.4.3 Previously ``'\\usepackage[utf8]{inputenc}'`` was used for all @@ -389,7 +395,7 @@ Keys that don't need to be overridden unless in special cases are: key is ignored. Default: ``'\\usepackage{textalpha}'`` or ``''`` if ``fontenc`` does not - include the ``LGR`` option. + include the ``LGR`` option. .. versionadded:: 2.0 @@ -407,7 +413,7 @@ Keys that don't need to be overridden unless in special cases are: <latexsphinxsetup>`. Default: ``'\\usepackage{geometry}'`` (or - ``'\\usepackage[dvipdfm]{geometry}'`` for Japanese documents) + ``'\\usepackage[dvipdfm]{geometry}'`` for Japanese documents) .. versionadded:: 1.5 @@ -784,14 +790,14 @@ macros may be significant. |warningbdcolors| The colour for the admonition frame. - Default: ``{rgb}{0,0,0}`` (black) + Default: ``{rgb}{0,0,0}`` (black) .. only:: latex |wgbdcolorslatex| The colour for the admonition frame. - Default: ``{rgb}{0,0,0}`` (black) + Default: ``{rgb}{0,0,0}`` (black) |warningbgcolors| The background colours for the respective admonitions. diff --git a/doc/man/sphinx-quickstart.rst b/doc/man/sphinx-quickstart.rst index 7da16ed1e..520a420ce 100644 --- a/doc/man/sphinx-quickstart.rst +++ b/doc/man/sphinx-quickstart.rst @@ -20,7 +20,7 @@ Options .. option:: -q, --quiet - Quiet mode that will skip interactive wizard to specify options. + Quiet mode that skips the interactive wizard for specifying options. This option requires `-p`, `-a` and `-v` options. .. option:: -h, --help, --version @@ -33,6 +33,10 @@ Options If specified, separate source and build directories. +.. option:: --no-sep + + If specified, create build directroy under source directroy. + .. option:: --dot=DOT Inside the root directory, two more directories will be created; diff --git a/doc/templating.rst b/doc/templating.rst index 0e3815c29..548f8b8d9 100644 --- a/doc/templating.rst +++ b/doc/templating.rst @@ -7,7 +7,7 @@ Templating ========== Sphinx uses the `Jinja <http://jinja.pocoo.org>`_ templating engine for its HTML -templates. Jinja is a text-based engine, and inspired by Django templates, so +templates. Jinja is a text-based engine, inspired by Django templates, so anyone having used Django will already be familiar with it. It also has excellent documentation for those who need to make themselves familiar with it. diff --git a/doc/theming.rst b/doc/theming.rst deleted file mode 100644 index 6a154affd..000000000 --- a/doc/theming.rst +++ /dev/null @@ -1,159 +0,0 @@ -.. highlight:: python - -HTML theming support -==================== - -.. versionadded:: 0.6 - -.. note:: - - This document provides information about creating your own theme. If you - simply wish to use a pre-existing HTML themes, refer to - :doc:`/usage/theming`. - -Sphinx supports changing the appearance of its HTML output via *themes*. A -theme is a collection of HTML templates, stylesheet(s) and other static files. -Additionally, it has a configuration file which specifies from which theme to -inherit, which highlighting style to use, and what options exist for customizing -the theme's look and feel. - -Themes are meant to be project-unaware, so they can be used for different -projects without change. - - -Creating themes ---------------- - -Themes take the form of either a directory or a zipfile (whose name is the -theme name), containing the following: - -* A :file:`theme.conf` file. -* HTML templates, if needed. -* A ``static/`` directory containing any static files that will be copied to the - output static directory on build. These can be images, styles, script files. - -The :file:`theme.conf` file is in INI format [1]_ (readable by the standard -Python :mod:`ConfigParser` module) and has the following structure: - -.. sourcecode:: ini - - [theme] - inherit = base theme - stylesheet = main CSS name - pygments_style = stylename - sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html - - [options] - variable = default value - -* The **inherit** setting gives the name of a "base theme", or ``none``. The - base theme will be used to locate missing templates (most themes will not have - to supply most templates if they use ``basic`` as the base theme), its options - will be inherited, and all of its static files will be used as well. If you - want to also inherit the stylesheet, include it via CSS' ``@import`` in your - own. - -* The **stylesheet** setting gives the name of a CSS file which will be - referenced in the HTML header. If you need more than one CSS file, either - include one from the other via CSS' ``@import``, or use a custom HTML template - that adds ``<link rel="stylesheet">`` tags as necessary. Setting the - :confval:`html_style` config value will override this setting. - -* The **pygments_style** setting gives the name of a Pygments style to use for - highlighting. This can be overridden by the user in the - :confval:`pygments_style` config value. - -* The **pygments_dark_style** setting gives the name of a Pygments style to use - for highlighting when the CSS media query ``(prefers-color-scheme: dark)`` - evaluates to true. It is injected into the page using - :meth:`~Sphinx.add_css_file()`. - -* The **sidebars** setting gives the comma separated list of sidebar templates - for constructing sidebars. This can be overridden by the user in the - :confval:`html_sidebars` config value. - -* The **options** section contains pairs of variable names and default values. - These options can be overridden by the user in :confval:`html_theme_options` - and are accessible from all templates as ``theme_<name>``. - -.. versionadded:: 1.7 - sidebar settings - - -.. _distribute-your-theme: - -Distribute your theme as a Python package ------------------------------------------ - -As a way to distribute your theme, you can use Python package. Python package -brings to users easy setting up ways. - -To distribute your theme as a Python package, please define an entry point -called ``sphinx.html_themes`` in your ``setup.py`` file, and write a ``setup()`` -function to register your themes using ``add_html_theme()`` API in it:: - - # 'setup.py' - setup( - ... - entry_points = { - 'sphinx.html_themes': [ - 'name_of_theme = your_package', - ] - }, - ... - ) - - # 'your_package.py' - from os import path - - def setup(app): - app.add_html_theme('name_of_theme', path.abspath(path.dirname(__file__))) - -If your theme package contains two or more themes, please call -``add_html_theme()`` twice or more. - -.. versionadded:: 1.2 - 'sphinx_themes' entry_points feature. - -.. deprecated:: 1.6 - ``sphinx_themes`` entry_points has been deprecated. - -.. versionadded:: 1.6 - ``sphinx.html_themes`` entry_points feature. - - -Templating ----------- - -The :doc:`guide to templating <templating>` is helpful if you want to write your -own templates. What is important to keep in mind is the order in which Sphinx -searches for templates: - -* First, in the user's ``templates_path`` directories. -* Then, in the selected theme. -* Then, in its base theme, its base's base theme, etc. - -When extending a template in the base theme with the same name, use the theme -name as an explicit directory: ``{% extends "basic/layout.html" %}``. From a -user ``templates_path`` template, you can still use the "exclamation mark" -syntax as described in the templating document. - -Static templates -~~~~~~~~~~~~~~~~ - -Since theme options are meant for the user to configure a theme more easily, -without having to write a custom stylesheet, it is necessary to be able to -template static files as well as HTML files. Therefore, Sphinx supports -so-called "static templates", like this: - -If the name of a file in the ``static/`` directory of a theme (or in the user's -static path, for that matter) ends with ``_t``, it will be processed by the -template engine. The ``_t`` will be left from the final file name. For -example, the *classic* theme has a file ``static/classic.css_t`` which uses -templating to put the color options into the stylesheet. When a documentation -is built with the classic theme, the output directory will contain a -``_static/classic.css`` file where all template tags have been processed. - -.. [1] It is not an executable Python file, as opposed to :file:`conf.py`, - because that would pose an unnecessary security risk if themes are - shared. diff --git a/doc/usage/advanced/intl.rst b/doc/usage/advanced/intl.rst index 11019a5d3..67d5e10e5 100644 --- a/doc/usage/advanced/intl.rst +++ b/doc/usage/advanced/intl.rst @@ -6,10 +6,10 @@ Internationalization .. versionadded:: 1.1 Complementary to translations provided for Sphinx-generated messages such as -navigation bars, Sphinx provides mechanisms facilitating *document* translations -in itself. See the :ref:`intl-options` for details on configuration. +navigation bars, Sphinx provides mechanisms facilitating the translation of +*documents*. See the :ref:`intl-options` for details on configuration. -.. figure:: /_static/translation.svg +.. figure:: /_static/translation.* :width: 100% Workflow visualization of translations in Sphinx. (The figure is created by diff --git a/doc/usage/builders/index.rst b/doc/usage/builders/index.rst index db6706944..c45a8062f 100644 --- a/doc/usage/builders/index.rst +++ b/doc/usage/builders/index.rst @@ -442,6 +442,10 @@ name is ``rinoh``. Refer to the `rinohtype manual`_ for details. Since Sphinx-1.5, the linkcheck builder comes to use requests module. + .. versionchanged:: 3.4 + + The linkcheck builder retries links when servers apply rate limits. + .. module:: sphinx.builders.xml .. class:: XMLBuilder diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index bc483fa1c..4fe20fc4e 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -70,9 +70,14 @@ Project information The author name(s) of the document. The default value is ``'unknown'``. .. confval:: copyright +.. confval:: project_copyright A copyright statement in the style ``'2008, Author Name'``. + .. versionchanged:: 3.5 + + As an alias, ``project_copyright`` is also allowed. + .. confval:: version The major project version, used as the replacement for ``|version|``. For @@ -316,6 +321,7 @@ General configuration * ``toc.circular`` * ``toc.secnum`` * ``epub.unknown_project_files`` + * ``epub.duplicated_toc_entry`` * ``autosectionlabel.*`` You can choose from these types. @@ -340,6 +346,10 @@ General configuration Added ``autosectionlabel.*`` + .. versionchanged:: 3.3.0 + + Added ``epub.duplicated_toc_entry`` + .. confval:: needs_sphinx If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will @@ -551,7 +561,7 @@ General configuration * Otherwise, the current time is formatted using :func:`time.strftime` and the format given in :confval:`today_fmt`. - The default is now :confval:`today` and a :confval:`today_fmt` of ``'%B %d, + The default is now :confval:`today` and a :confval:`today_fmt` of ``'%b %d, %Y'`` (or, if translation is enabled with :confval:`language`, an equivalent format for the selected locale). @@ -572,12 +582,27 @@ General configuration .. confval:: highlight_options - A dictionary of options that modify how the lexer specified by - :confval:`highlight_language` generates highlighted source code. These are - lexer-specific; for the options understood by each, see the - `Pygments documentation <https://pygments.org/docs/lexers>`_. + A dictionary that maps language names to options for the lexer modules of + Pygments. These are lexer-specific; for the options understood by each, + see the `Pygments documentation <https://pygments.org/docs/lexers>`_. + + Example:: + + highlight_options = { + 'default': {'stripall': True}, + 'php': {'startinline': True}, + } + + A single dictionary of options are also allowed. Then it is recognized + as options to the lexer specified by :confval:`highlight_language`:: + + # configuration for the ``highlight_language`` + highlight_options = {'stripall': True} .. versionadded:: 1.3 + .. versionchanged:: 3.5 + + Allow to configure highlight options for multiple languages .. confval:: pygments_style @@ -660,10 +685,11 @@ documentation on :ref:`intl` for details. generated by Sphinx will be in that language. Also, Sphinx will try to substitute individual paragraphs from your documents with the translation sets obtained from :confval:`locale_dirs`. Sphinx will search - language-specific figures named by `figure_language_filename` and substitute - them for original figures. In the LaTeX builder, a suitable language will - be selected as an option for the *Babel* package. Default is ``None``, - which means that no translation will be done. + language-specific figures named by :confval:`figure_language_filename` + (e.g. the German version of ``myfigure.png`` will be ``myfigure.de.png`` + by default setting) and substitute them for original figures. In the LaTeX + builder, a suitable language will be selected as an option for the *Babel* + package. Default is ``None``, which means that no translation will be done. .. versionadded:: 0.5 @@ -755,9 +781,15 @@ documentation on :ref:`intl` for details. If true, a document's text domain is its docname if it is a top-level project file and its very base directory otherwise. + If set to string, all document's text domain is this string, making all + documents use single text domain. + By default, the document ``markup/code.rst`` ends up in the ``markup`` text domain. With this option set to ``False``, it is ``markup/code``. + .. versionchanged:: 3.3 + The string value is now accepted. + .. confval:: gettext_uuid If true, Sphinx generates uuid information for version tracking in message @@ -820,6 +852,8 @@ documentation on :ref:`intl` for details. extension, e.g. ``dirname/filename`` * ``{path}`` - the directory path component of the filename, with a trailing slash if non-empty, e.g. ``dirname/`` + * ``{docpath}`` - the directory path component for the current document, with + a trailing slash if non-empty. * ``{basename}`` - the filename without the directory path or file extension components, e.g. ``filename`` * ``{ext}`` - the file extension, e.g. ``.png`` @@ -833,6 +867,9 @@ documentation on :ref:`intl` for details. .. versionchanged:: 1.5 Added ``{path}`` and ``{basename}`` tokens. + .. versionchanged:: 3.2 + Added ``{docpath}`` token. + .. _math-options: @@ -912,7 +949,7 @@ that use Sphinx's HTMLWriter class. .. confval:: html_short_title - A shorter "title" for the HTML docs. This is used in for links in the + A shorter "title" for the HTML docs. This is used for links in the header and in the HTML Help docs. If not given, it defaults to the value of :confval:`html_title`. @@ -920,11 +957,23 @@ that use Sphinx's HTMLWriter class. .. confval:: html_baseurl - The URL which points to the root of the HTML documentation. It is used to - indicate the location of document like ``canonical_url``. + The base URL which points to the root of the HTML documentation. It is used + to indicate the location of document using `The Canonical Link Relation`_. + Default: ``''``. + + .. _The Canonical Link Relation: https://tools.ietf.org/html/rfc6596 .. versionadded:: 1.8 +.. confval:: html_codeblock_linenos_style + + The style of line numbers for code-blocks. + + * ``'table'`` -- display line numbers using ``<table>`` tag (default) + * ``'inline'`` -- display line numbers using ``<span>`` tag + + .. versionadded:: 3.2 + .. confval:: html_context A dictionary of values to pass into the template engine's context for all @@ -970,7 +1019,14 @@ that use Sphinx's HTMLWriter class. 'https://example.com/css/custom.css', ('print.css', {'media': 'print'})] + As a special attribute, *priority* can be set as an integer to load the CSS + file earlier or lazier step. For more information, refer + :meth:`Sphinx.add_css_files()`. + .. versionadded:: 1.8 + .. versionchanged:: 3.5 + + Support priority attribute .. confval:: html_js_files @@ -986,7 +1042,14 @@ that use Sphinx's HTMLWriter class. 'https://example.com/scripts/custom.js', ('custom.js', {'async': 'async'})] + As a special attribute, *priority* can be set as an integer to load the CSS + file earlier or lazier step. For more information, refer + :meth:`Sphinx.add_css_files()`. + .. versionadded:: 1.8 + .. versionchanged:: 3.5 + + Support priority attribute .. confval:: html_static_path @@ -1070,6 +1133,23 @@ that use Sphinx's HTMLWriter class. This can now be a string to select the actual text of the link. Previously, only boolean values were accepted. + .. deprecated:: 3.5 + This has been replaced by :confval:`html_permalinks` + +.. confval:: html_permalinks + + If true, Sphinx will add "permalinks" for each heading and description + environment. Default: ``True``. + + .. versionadded:: 3.5 + +.. confval:: html_permalinks_icon + + A text for permalinks for each heading and description environment. HTML + tags are allowed. Default: a paragraph sign; ``¶`` + + .. versionadded:: 3.5 + .. confval:: html_sidebars Custom sidebar templates, must be a dictionary that maps document names to @@ -2224,6 +2304,12 @@ These options influence manual page output. .. versionadded:: 1.1 +.. confval:: man_make_section_directory + + If true, make a section directory on build man page. Default is False. + + .. versionadded:: 3.3 + .. _texinfo-options: @@ -2390,6 +2476,32 @@ Options for the linkcheck builder .. versionadded:: 1.1 +.. confval:: linkcheck_request_headers + + A dictionary that maps baseurls to HTTP request headers. + + The key is a URL base string like ``"https://sphinx-doc.org/"``. To specify + headers for other hosts, ``"*"`` can be used. It matches all hosts only when + the URL does not match other settings. + + The value is a dictionary that maps header name to its value. + + Example: + + .. code-block:: python + + linkcheck_request_headers = { + "https://sphinx-doc.org/": { + "Accept": "text/html", + "Accept-Encoding": "utf-8", + }, + "*": { + "Accept": "text/html,application/xhtml+xml", + } + } + + .. versionadded:: 3.1 + .. confval:: linkcheck_retries The number of times the linkcheck builder will attempt to check a URL before @@ -2467,6 +2579,23 @@ Options for the linkcheck builder .. versionadded:: 2.3 +.. confval:: linkcheck_rate_limit_timeout + + The ``linkcheck`` builder may issue a large number of requests to the same + site over a short period of time. This setting controls the builder behavior + when servers indicate that requests are rate-limited. + + If a server indicates when to retry (using the `Retry-After`_ header), + ``linkcheck`` always follows the server indication. + + Otherwise, ``linkcheck`` waits for a minute before to retry and keeps + doubling the wait time between attempts until it succeeds or exceeds the + ``linkcheck_rate_limit_timeout``. By default, the timeout is 5 minutes. + + .. _Retry-After: https://tools.ietf.org/html/rfc7231#section-7.1.3 + + .. versionadded:: 3.4 + Options for the XML builder --------------------------- @@ -2509,6 +2638,23 @@ Options for the C domain .. versionadded:: 3.0 +.. confval:: c_allow_pre_v3 + + A boolean (default ``False``) controlling whether to parse and try to + convert pre-v3 style type directives and type roles. + + .. versionadded:: 3.2 + .. deprecated:: 3.2 + Use the directives and roles added in v3. + +.. confval:: c_warn_on_allowed_pre_v3 + + A boolean (default ``True``) controlling whether to warn when a pre-v3 + style type directive/role is parsed and converted. + + .. versionadded:: 3.2 + .. deprecated:: 3.2 + Use the directives and roles added in v3. .. _cpp-config: diff --git a/doc/usage/extensions/autodoc.rst b/doc/usage/extensions/autodoc.rst index ec1d6c9b5..5222592ab 100644 --- a/doc/usage/extensions/autodoc.rst +++ b/doc/usage/extensions/autodoc.rst @@ -136,15 +136,28 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, :undoc-members: * "Private" members (that is, those named like ``_private`` or ``__private``) - will be included if the ``private-members`` flag option is given. + 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: - .. code-block:: rst + .. code-block:: python def my_function(my_arg, my_other_arg): """blah blah blah @@ -159,7 +172,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, an underscore. For example: - .. code-block:: rst + .. code-block:: python def _my_function(my_arg, my_other_arg): """blah blah blah @@ -169,6 +182,16 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, .. versionadded:: 3.1 + * autodoc considers a variable member does not have any default value if its + docstring contains ``:meta hide-value:`` in its :ref:`info-field-lists`. + Example: + + .. code-block:: python + + var1 = None #: :meta hide-value: + + .. versionadded:: 3.5 + * Python "special" members (that is, those named like ``__special__``) will be included if the ``special-members`` flag option is given:: @@ -216,7 +239,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, .. versionchanged:: 3.0 - It takes an anchestor class name as an argument. + It takes an ancestor class name as an argument. * It's possible to override the signature for explicitly documented callable objects (functions, methods, classes) with the regular syntax that will @@ -280,6 +303,12 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, .. versionadded:: 1.3 + * As a hint to autodoc extension, you can put a ``::`` separator in between + module name and object name to let autodoc know the correct module name if + it is ambiguous. :: + + .. autoclass:: module.name::Noodle + .. rst:directive:: autofunction autodecorator @@ -307,6 +336,15 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, By default, without ``annotation`` option, Sphinx tries to obtain the value of the variable and print it after the name. + The ``no-value`` option can be used instead of a blank ``annotation`` to show the + type hint but not the value:: + + .. autodata:: CD_DRIVE + :no-value: + + If both the ``annotation`` and ``no-value`` options are used, ``no-value`` has no + effect. + For module data members and class attributes, documentation can either be put into a comment with special formatting (using a ``#:`` to start the comment instead of just ``#``), or in a docstring *after* the definition. Comments @@ -346,6 +384,9 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, option. .. versionchanged:: 2.0 :rst:dir:`autodecorator` added. + .. versionchanged:: 3.4 + :rst:dir:`autodata` and :rst:dir:`autoattribute` now have a ``no-value`` + option. .. note:: @@ -496,6 +537,44 @@ There are also config values that you can set: New option ``'description'`` is added. +.. confval:: autodoc_type_aliases + + A dictionary for users defined `type aliases`__ that maps a type name to the + full-qualified object name. It is used to keep type aliases not evaluated in + the document. Defaults to empty (``{}``). + + The type aliases are only available if your program enables `Postponed + Evaluation of Annotations (PEP 563)`__ feature via ``from __future__ import + annotations``. + + For example, there is code using a type alias:: + + from __future__ import annotations + + AliasType = Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]] + + def f() -> AliasType: + ... + + If ``autodoc_type_aliases`` is not set, autodoc will generate internal mark-up + from this code as following:: + + .. py:function:: f() -> Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]] + + ... + + If you set ``autodoc_type_aliases`` as + ``{'AliasType': 'your.module.AliasType'}``, it generates the following document + internally:: + + .. py:function:: f() -> your.module.AliasType: + + ... + + .. __: https://www.python.org/dev/peps/pep-0563/ + .. __: https://mypy.readthedocs.io/en/latest/kinds_of_types.html#type-aliases + .. versionadded:: 3.3 + .. 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 38d18361e..03ea7548e 100644 --- a/doc/usage/extensions/autosummary.rst +++ b/doc/usage/extensions/autosummary.rst @@ -175,7 +175,7 @@ also use these config values: .. confval:: autosummary_generate_overwrite - If true, autosummary already overwrites stub files by generated contents. + If true, autosummary overwrites existing files by generated stub pages. Defaults to true (enabled). .. versionadded:: 3.0 @@ -195,6 +195,15 @@ also use these config values: .. versionadded:: 2.1 +.. confval:: autosummary_filename_map + + A dict mapping object names to filenames. This is necessary to avoid + filename conflicts where multiple objects have names that are + indistinguishable when case is ignored, on file systems where filenames + are case-insensitive. + + .. versionadded:: 3.2 + Customizing templates --------------------- @@ -295,7 +304,7 @@ The following variables available in the templates: .. data:: modules List containing names of "public" modules in the package. Only available for - modules that are packages. + modules that are packages and the ``recursive`` option is on. .. versionadded:: 3.1 diff --git a/doc/usage/extensions/coverage.rst b/doc/usage/extensions/coverage.rst index 46d31053c..5e6b04feb 100644 --- a/doc/usage/extensions/coverage.rst +++ b/doc/usage/extensions/coverage.rst @@ -51,4 +51,11 @@ should check: .. versionadded:: 1.1 -.. _Python regular expressions: https://docs.python.org/library/re
\ No newline at end of file +.. confval:: coverage_show_missing_items + + Print objects that are missing to standard output also. + ``False`` by default. + + .. versionadded:: 3.1 + +.. _Python regular expressions: https://docs.python.org/library/re diff --git a/doc/usage/extensions/doctest.rst b/doc/usage/extensions/doctest.rst index 33d6cf016..0fe9b535d 100644 --- a/doc/usage/extensions/doctest.rst +++ b/doc/usage/extensions/doctest.rst @@ -67,7 +67,7 @@ a comma-separated list of group names. default set of flags is specified by the :confval:`doctest_default_flags` configuration variable. - This directive supports three options: + This directive supports five options: * ``hide``, a flag option, hides the doctest block in other builders. By default it is shown as a highlighted doctest block. @@ -102,6 +102,11 @@ a comma-separated list of group names. Supported PEP-440 operands and notations + * ``trim-doctest-flags`` and ``no-trim-doctest-flags``, a flag option, + doctest flags (comments looking like ``# doctest: FLAG, ...``) at the + ends of lines and ``<BLANKLINE>`` markers are removed (or not removed) + individually. Default is ``trim-doctest-flags``. + Note that like with standard doctests, you have to use ``<BLANKLINE>`` to signal a blank line in the expected output. The ``<BLANKLINE>`` is removed when building presentation output (HTML, LaTeX etc.). @@ -119,11 +124,16 @@ a comma-separated list of group names. A code block for a code-output-style test. - This directive supports one option: + This directive supports three options: * ``hide``, a flag option, hides the code block in other builders. By default it is shown as a highlighted code block. + * ``trim-doctest-flags`` and ``no-trim-doctest-flags``, a flag option, + doctest flags (comments looking like ``# doctest: FLAG, ...``) at the + ends of lines and ``<BLANKLINE>`` markers are removed (or not removed) + individually. Default is ``trim-doctest-flags``. + .. note:: Code in a ``testcode`` block is always executed all at once, no matter how @@ -149,7 +159,7 @@ a comma-separated list of group names. The corresponding output, or the exception message, for the last :rst:dir:`testcode` block. - This directive supports two options: + This directive supports four options: * ``hide``, a flag option, hides the output block in other builders. By default it is shown as a literal block without highlighting. @@ -157,6 +167,11 @@ a comma-separated list of group names. * ``options``, a string option, can be used to give doctest flags (comma-separated) just like in normal doctest blocks. + * ``trim-doctest-flags`` and ``no-trim-doctest-flags``, a flag option, + doctest flags (comments looking like ``# doctest: FLAG, ...``) at the + ends of lines and ``<BLANKLINE>`` markers are removed (or not removed) + individually. Default is ``trim-doctest-flags``. + Example:: .. testcode:: diff --git a/doc/usage/extensions/example_google.py b/doc/usage/extensions/example_google.py index 97ffe8a05..5fde6e226 100644 --- a/doc/usage/extensions/example_google.py +++ b/doc/usage/extensions/example_google.py @@ -294,3 +294,21 @@ class ExampleClass: def _private_without_docstring(self): pass + +class ExamplePEP526Class: + """The summary line for a class docstring should fit on one line. + + If the class has public attributes, they may be documented here + in an ``Attributes`` section and follow the same formatting as a + function's ``Args`` section. If ``napoleon_attr_annotations`` + is True, types can be specified in the class body using ``PEP 526`` + annotations. + + Attributes: + attr1: Description of `attr1`. + attr2: Description of `attr2`. + + """ + + attr1: str + attr2: int
\ No newline at end of file diff --git a/doc/usage/extensions/intersphinx.rst b/doc/usage/extensions/intersphinx.rst index 619ec8c20..178655cae 100644 --- a/doc/usage/extensions/intersphinx.rst +++ b/doc/usage/extensions/intersphinx.rst @@ -75,8 +75,9 @@ linking: A dictionary mapping unique identifiers to a tuple ``(target, inventory)``. Each ``target`` is the base URI of a foreign Sphinx documentation set and can be a local path or an HTTP URI. The ``inventory`` indicates where the - inventory file can be found: it can be ``None`` (at the same location as - the base URI) or another local or HTTP URI. + inventory file can be found: it can be ``None`` (an :file:`objects.inv` file + at the same location as the base URI) or another local file path or a full + HTTP URI to an inventory file. The unique identifier can be used to prefix cross-reference targets, so that it is clear which intersphinx set the target belongs to. A link like @@ -106,7 +107,7 @@ linking: ``https://docs.python.org/3``. It is up to you to update the inventory file as new objects are added to the Python documentation. - **Multiple target for the inventory** + **Multiple targets for the inventory** .. versionadded:: 1.3 @@ -120,6 +121,16 @@ linking: intersphinx_mapping = {'python': ('https://docs.python.org/3', (None, 'python-inv.txt'))} + For a set of books edited and tested locally and then published + together, it could be helpful to try a local inventory file first, + to check references before publication:: + + intersphinx_mapping = { + 'otherbook': + ('https://myproj.readthedocs.io/projects/otherbook/en/latest', + ('../../otherbook/build/html/objects.inv', None)), + } + .. confval:: intersphinx_cache_limit The maximum number of days to cache remote inventories. The default is diff --git a/doc/usage/extensions/napoleon.rst b/doc/usage/extensions/napoleon.rst index b12dd03ba..066c56e2d 100644 --- a/doc/usage/extensions/napoleon.rst +++ b/doc/usage/extensions/napoleon.rst @@ -115,6 +115,7 @@ All of the following section headers are supported: * ``Parameters`` * ``Return`` *(alias of Returns)* * ``Returns`` + * ``Raise`` *(alias of Raises)* * ``Raises`` * ``References`` * ``See Also`` @@ -122,6 +123,7 @@ All of the following section headers are supported: * ``Todo`` * ``Warning`` * ``Warnings`` *(alias of Warning)* + * ``Warn`` *(alias of Warns)* * ``Warns`` * ``Yield`` *(alias of Yields)* * ``Yields`` @@ -201,7 +203,8 @@ Type Annotations This is an alternative to expressing types directly in docstrings. One benefit of expressing types according to `PEP 484`_ is that type checkers and IDEs can take advantage of them for static code -analysis. +analysis. `PEP 484`_ was then extended by `PEP 526`_ which introduced +a similar way to annotate variables (and attributes). Google style with Python 3 type annotations:: @@ -219,6 +222,19 @@ Google style with Python 3 type annotations:: """ return True + + class Class: + """Summary line. + + Extended description of class + + Attributes: + attr1: Description of attr1 + attr2: Description of attr2 + """ + + attr1: int + attr2: str Google style with types in docstrings:: @@ -236,6 +252,16 @@ Google style with types in docstrings:: """ return True + + class Class: + """Summary line. + + Extended description of class + + Attributes: + attr1 (int): Description of attr1 + attr2 (str): Description of attr2 + """ .. Note:: `Python 2/3 compatible annotations`_ aren't currently @@ -244,6 +270,9 @@ Google style with types in docstrings:: .. _PEP 484: https://www.python.org/dev/peps/pep-0484/ +.. _PEP 526: + https://www.python.org/dev/peps/pep-0526/ + .. _Python 2/3 compatible annotations: https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code @@ -272,11 +301,13 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`:: napoleon_use_ivar = False napoleon_use_param = True napoleon_use_rtype = True + napoleon_type_aliases = None + napoleon_attr_annotations = True .. _Google style: https://google.github.io/styleguide/pyguide.html .. _NumPy style: - https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt + https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard .. confval:: napoleon_google_docstring @@ -433,7 +464,7 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`:: :param arg1: Description of `arg1` :type arg1: str :param arg2: Description of `arg2`, defaults to 0 - :type arg2: int, optional + :type arg2: :class:`int`, *optional* **If False**:: @@ -478,3 +509,65 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`:: **If False**:: :returns: *bool* -- True if successful, False otherwise + +.. confval:: napoleon_type_aliases + + A mapping to translate type names to other names or references. Works + only when ``napoleon_use_param = True``. *Defaults to None.* + + With:: + + napoleon_type_aliases = { + "CustomType": "mypackage.CustomType", + "dict-like": ":term:`dict-like <mapping>`", + } + + This `NumPy style`_ snippet:: + + Parameters + ---------- + arg1 : CustomType + Description of `arg1` + arg2 : dict-like + Description of `arg2` + + becomes:: + + :param arg1: Description of `arg1` + :type arg1: mypackage.CustomType + :param arg2: Description of `arg2` + :type arg2: :term:`dict-like <mapping>` + + .. versionadded:: 3.2 + +.. confval:: napoleon_attr_annotations + + True to allow using `PEP 526`_ attributes annotations in classes. + If an attribute is documented in the docstring without a type and + has an annotation in the class body, that type is used. + + .. versionadded:: 3.4 + +.. confval:: napoleon_custom_sections + + Add a list of custom sections to include, expanding the list of parsed sections. + *Defaults to None.* + + The entries can either be strings or tuples, depending on the intention: + + * To create a custom "generic" section, just pass a string. + * To create an alias for an existing section, pass a tuple containing the + alias name and the original, in that order. + * To create a custom section that displays like the parameters or returns + section, pass a tuple containing the custom section name and a string + value, "params_style" or "returns_style". + + If an entry is just a string, it is interpreted as a header for a generic + section. If the entry is a tuple/list/indexed container, the first entry + is the name of the section, the second is the section key to emulate. If the + second entry value is "params_style" or "returns_style", the custom section + will be displayed like the parameters section or returns section. + + .. versionadded:: 1.8 + .. versionchanged:: 3.5 + Support ``params_style`` and ``returns_style``
\ No newline at end of file diff --git a/doc/usage/installation.rst b/doc/usage/installation.rst index c9bef974d..46ef6a51e 100644 --- a/doc/usage/installation.rst +++ b/doc/usage/installation.rst @@ -171,7 +171,7 @@ Docker images for Sphinx are published on the `Docker Hub <https://hub.docker.co - `sphinxdoc/sphinx <https://hub.docker.com/repository/docker/sphinxdoc/sphinx>`_ - `sphinxdoc/sphinx-latexpdf <https://hub.docker.com/repository/docker/sphinxdoc/sphinx-latexpdf>`_ -Former one is used for standard usage of Sphinx, and latter one is mainly used for PDF builds using LaTeX. +Former one is used for standard usage of Sphinx, and latter one is mainly used for PDF builds using LaTeX. Please choose one for your purpose. .. note:: diff --git a/doc/usage/quickstart.rst b/doc/usage/quickstart.rst index 8d2de021e..1d7e540a6 100644 --- a/doc/usage/quickstart.rst +++ b/doc/usage/quickstart.rst @@ -15,7 +15,7 @@ Much of Sphinx's power comes from the richness of its default plain-text markup format, :doc:`reStructuredText </usage/restructuredtext/index>`, along with it's :doc:`significant extensibility capabilities </development/index>`. -The goal of this document is to give you a quick taste of what Sphinx it is and +The goal of this document is to give you a quick taste of what Sphinx is and how you might use it. When you're done here, you can check out the :doc:`installation guide </usage/installation>` followed by the intro to the default markup format used by Sphinx, :doc:`reStucturedText diff --git a/doc/usage/restructuredtext/directives.rst b/doc/usage/restructuredtext/directives.rst index 7b9bd2f80..e8b88c21b 100644 --- a/doc/usage/restructuredtext/directives.rst +++ b/doc/usage/restructuredtext/directives.rst @@ -114,9 +114,9 @@ tables of contents. The ``toctree`` directive is the central element. **Additional options** - You can use ``caption`` option to provide a toctree caption and you can use - ``name`` option to provide implicit target name that can be referenced by - using :rst:role:`ref`:: + You can use the ``caption`` option to provide a toctree caption and you can + use the ``name`` option to provide an implicit target name that can be + referenced by using :rst:role:`ref`:: .. toctree:: :caption: Table of Contents @@ -246,7 +246,7 @@ The special document names (and pages generated for them) are: * every name beginning with ``_`` - Though only few such names are currently used by Sphinx, you should not + Though few such names are currently used by Sphinx, you should not create documents or document-containing directories with such names. (Using ``_`` as a prefix for a custom template directory is fine.) @@ -569,12 +569,28 @@ __ http://pygments.org/docs/lexers print 'Explicit is better than implicit.' + In order to cross-reference a code-block using either the + :rst:role:`ref` or the :rst:role:`numref` role, it is necessary + that both :strong:`name` and :strong:`caption` be defined. The + argument of :strong:`name` can then be given to :rst:role:`numref` + to generate the cross-reference. Example:: + + See :numref:`this-py` for an example. + + When using :rst:role:`ref`, it is possible to generate a cross-reference + with only :strong:`name` defined, provided an explicit title is + given. Example:: + + See :ref:`this code snippet <this-py>` for an example. + .. versionadded:: 1.3 .. rst:directive:option:: dedent: number - :type: number + :type: number or no value - Strip indentation characters from the code block. For example:: + Strip indentation characters from the code block. When number given, + leading N characters are removed. When no argument given, leading spaces + are removed via :func:`textwrap.dedent()`. For example:: .. code-block:: ruby :dedent: 4 @@ -582,6 +598,8 @@ __ http://pygments.org/docs/lexers some ruby code .. versionadded:: 1.3 + .. versionchanged:: 3.5 + Support automatic dedent. .. rst:directive:option:: force :type: no value @@ -656,9 +674,43 @@ __ http://pygments.org/docs/lexers string are included. The ``start-at`` and ``end-at`` options behave in a similar way, but the lines containing the matched string are included. - With lines selected using ``start-after`` it is still possible to use - ``lines``, the first allowed line having by convention the line number - ``1``. + ``start-after``/``start-at`` and ``end-before``/``end-at`` can have same string. + ``start-after``/``start-at`` filter lines before the line that contains + option string (``start-at`` will keep the line). Then ``end-before``/``end-at`` + filter lines after the line that contains option string (``end-at`` will keep + the line and ``end-before`` skip the first line). + + .. note:: + + If you want to select only ``[second-section]`` of ini file like the + following, you can use ``:start-at: [second-section]`` and + ``:end-before: [third-section]``: + + .. code-block:: ini + + [first-section] + + var_in_first=true + + [second-section] + + var_in_second=true + + [third-section] + + var_in_third=true + + Useful cases of these option is working with tag comments. + ``:start-after: [initialized]`` and ``:end-before: [initialized]`` options + keep lines between comments: + + .. code-block:: py + + if __name__ == "__main__": + # [initialize] + app.start(":8000") + # [initialize] + When lines have been selected in any of the ways described above, the line numbers in ``emphasize-lines`` refer to those selected lines, counted @@ -708,6 +760,9 @@ __ http://pygments.org/docs/lexers .. versionchanged:: 2.1 Added the ``force`` option. + .. versionchanged:: 3.5 + Support automatic dedent. + .. _glossary-directive: Glossary @@ -1165,20 +1220,29 @@ the definition of the symbol. There is this directive: the following definition. If the definition spans multiple lines, each continuation line must begin with a colon placed at the same column as in the first line. + Blank lines are not allowed within ``productionlist`` directive arguments. + + The definition can contain token names which are marked as interpreted text + (e.g., "``sum ::= `integer` "+" `integer```") -- this generates + cross-references to the productions of these tokens. Outside of the + production list, you can reference to token productions using + :rst:role:`token`. The *productionGroup* argument to :rst:dir:`productionlist` serves to distinguish different sets of production lists that belong to different grammars. Multiple production lists with the same *productionGroup* thus define rules in the same scope. - Blank lines are not allowed within ``productionlist`` directive arguments. + Inside of the production list, tokens implicitly refer to productions + from the current group. You can refer to the production of another + grammar by prefixing the token with its group name and a colon, e.g, + "``otherGroup:sum``". If the group of the token should not be shown in + the production, it can be prefixed by a tilde, e.g., + "``~otherGroup:sum``". To refer to a production from an unnamed + grammar, the token should be prefixed by a colon, e.g., "``:sum``". - The definition can contain token names which are marked as interpreted text - (e.g. "``sum ::= `integer` "+" `integer```") -- this generates - cross-references to the productions of these tokens. Outside of the - production list, you can reference to token productions using - :rst:role:`token`. - However, if you have given a *productionGroup* argument you must prefix the + Outside of the production list, + if you have given a *productionGroup* argument you must prefix the token name in the cross-reference with the group name and a colon, e.g., "``myGroup:sum``" instead of just "``sum``". If the group should not be shown in the title of the link either diff --git a/doc/usage/restructuredtext/domains.rst b/doc/usage/restructuredtext/domains.rst index 9559acf22..f3754ab7c 100644 --- a/doc/usage/restructuredtext/domains.rst +++ b/doc/usage/restructuredtext/domains.rst @@ -42,9 +42,22 @@ Basic Markup Most domains provide a number of :dfn:`object description directives`, used to describe specific objects provided by modules. Each directive requires one or more signatures to provide basic information about what is being described, and -the content should be the description. The basic version makes entries in the -general index; if no index entry is desired, you can give the directive option -flag ``:noindex:``. An example using a Python domain directive:: +the content should be the description. A domain will typically keep an +internal index of all entites to aid cross-referencing. Typically it will +also add entries in the shown general index. +If you want to suppress the addition of an entry in the shown index, you can +give the directive option flag ``:noindexentry:``. +If you want to typeset an object description, without even making it available +for cross-referencing, you can give the directive option flag ``:noindex:`` +(which implies ``:noindexentry:``). +Though, note that not every directive en every domain may support these +options. + +.. versionadded:: 3.2 + The directive option ``noindexentry`` in the Python, C, C++, and Javascript + domains. + +An example using a Python domain directive:: .. py:function:: spam(eggs) ham(eggs) @@ -699,6 +712,53 @@ Explicit ref: :c:var:`Data.@data.a`. Short-hand ref: :c:var:`Data.a`. .. versionadded:: 3.0 +Aliasing Declarations +~~~~~~~~~~~~~~~~~~~~~ + +.. c:namespace-push:: @alias + +Sometimes it may be helpful list declarations elsewhere than their main +documentation, e.g., when creating a synopsis of an interface. +The following directive can be used for this purpose. + +.. rst:directive:: .. c:alias:: name + + Insert one or more alias declarations. Each entity can be specified + as they can in the :rst:role:`c:any` role. + + For example:: + + .. c:var:: int data + .. c:function:: int f(double k) + + .. c:alias:: data + f + + becomes + + .. c:var:: int data + .. c:function:: int f(double k) + + .. c:alias:: data + f + + .. versionadded:: 3.2 + + + .. rubric:: Options + + .. rst:directive:option:: maxdepth: int + + Insert nested declarations as well, up to the total depth given. + Use 0 for infinite depth and 1 for just the mentioned declaration. + Defaults to 1. + + .. versionadded:: 3.3 + + +.. c:namespace-pop:: + + Inline Expressions and Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1038,7 +1098,7 @@ Options Some directives support options: -- ``:noindex:``, see :ref:`basic-domain-markup`. +- ``:noindexentry:``, see :ref:`basic-domain-markup`. - ``:tparam-line-spec:``, for templated declarations. If specified, each template parameter will be rendered on a separate line. diff --git a/doc/usage/restructuredtext/field-lists.rst b/doc/usage/restructuredtext/field-lists.rst index 28b3cfe1b..5fc897d62 100644 --- a/doc/usage/restructuredtext/field-lists.rst +++ b/doc/usage/restructuredtext/field-lists.rst @@ -9,7 +9,14 @@ fields marked up like this:: :fieldname: Field content -Sphinx provides custom behavior for bibliographic fields compared to docutils. +Sphinx extends standard docutils behavior for field lists and adds some extra +functionality that is covered in this section. + +.. note:: + + The values of field lists will be parsed as + strings. You cannot use Python collections such as lists or dictionaries. + .. _metadata: @@ -17,11 +24,20 @@ File-wide metadata ------------------ A field list near the top of a file is normally parsed by docutils as the -*docinfo* which is generally used to record the author, date of publication and -other metadata. However, in Sphinx, a field list preceding any other markup is -moved from the *docinfo* to the Sphinx environment as document metadata and is -not displayed in the output; a field list appearing after the document title -will be part of the *docinfo* as normal and will be displayed in the output. +*docinfo* and shown on the page. However, in Sphinx, a field list preceding +any other markup is moved from the *docinfo* to the Sphinx environment as +document metadata, and is not displayed in the output. + +.. note:: + + A field list appearing after the document title *will* be part of the + *docinfo* as normal and will be displayed in the output. + + +Special metadata fields +----------------------- + +Sphinx provides custom behavior for bibliographic fields compared to docutils. At the moment, these metadata fields are recognized: diff --git a/doc/usage/theming.rst b/doc/usage/theming.rst index 792a4a53d..fb06e8741 100644 --- a/doc/usage/theming.rst +++ b/doc/usage/theming.rst @@ -2,8 +2,8 @@ .. _html-themes: -HTML -==== +HTML Theming +============ Sphinx provides a number of builders for HTML and HTML-based formats. @@ -21,7 +21,8 @@ Themes .. note:: This section provides information about using pre-existing HTML themes. If - you wish to create your own theme, refer to :doc:`/theming`. + you wish to create your own theme, refer to + :doc:`/development/theming`. Sphinx supports changing the appearance of its HTML output via *themes*. A theme is a collection of HTML templates, stylesheet(s) and other static files. @@ -80,7 +81,7 @@ zipfile-based theme:: html_theme = "dotted" For more information on the design of themes, including information about -writing your own themes, refer to :doc:`/theming`. +writing your own themes, refer to :doc:`/development/theming`. .. _builtin-themes: @@ -172,6 +173,12 @@ These themes are: .. versionadded:: 3.1 + - **globaltoc_maxdepth** (int): The maximum depth of the toctree in + ``globaltoc.html`` (see :confval:`html_sidebars`). Set it to -1 to allow + unlimited depth. Defaults to the max depth selected in the toctree directive. + + .. versionadded:: 3.2 + **alabaster** `Alabaster theme`_ is a modified "Kr" Sphinx theme from @kennethreitz (especially as used in his Requests project), which was itself originally @@ -341,7 +348,7 @@ Third Party Themes There are many third-party themes available. Some of these are general use, while others are specific to an individual project. A section of third-party -themes is listed below. Many more can be found on PyPI__, GitHub__ and +themes is listed below. Many more can be found on PyPI__, GitHub__, GitLab__ and sphinx-themes.org__. .. cssclass:: clear @@ -357,6 +364,8 @@ sphinx-themes.org__. .. versionchanged:: 1.4 **sphinx_rtd_theme** has become optional. + .. __: https://pypi.org/search/?q=&o=&c=Framework+%3A%3A+Sphinx+%3A%3A+Theme .. __: https://github.com/search?utf8=%E2%9C%93&q=sphinx+theme&type= +.. __: https://gitlab.com/explore?name=sphinx+theme .. __: https://sphinx-themes.org/ diff --git a/package-lock.json b/package-lock.json index 469127026..087afcf3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -385,12 +385,6 @@ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, - "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", - "dev": true - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -535,14 +529,22 @@ } }, "http-proxy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "requires": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" + }, + "dependencies": { + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + } } }, "iconv-lite": { @@ -702,9 +704,9 @@ } }, "lodash": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "log4js": { @@ -29,9 +29,11 @@ directory = sphinx/locale/ [flake8] max-line-length = 95 ignore = E116,E241,E251,E741,W504,I101 -exclude = .git,.tox,.venv,tests/*,build/*,doc/_build/*,sphinx/search/*,doc/usage/extensions/example*.py +exclude = .git,.tox,.venv,tests/roots/*,build/*,doc/_build/*,sphinx/search/*,doc/usage/extensions/example*.py application-import-names = sphinx import-order-style = smarkets +per-file-ignores = + tests/*: E501 [flake8:local-plugins] extension = @@ -39,6 +41,9 @@ extension = paths = . +[isort] +line_length = 95 + [mypy] python_version = 3.5 disallow_incomplete_defs = True @@ -55,12 +60,11 @@ filterwarnings = all ignore::DeprecationWarning:docutils.io ignore::DeprecationWarning:pyximport.pyximport + ignore::ImportWarning:importlib._bootstrap ignore::PendingDeprecationWarning:sphinx.util.pycompat markers = - sphinx apidoc setup_command - test_params testpaths = tests [coverage:run] @@ -43,15 +43,15 @@ extras_require = { ], 'lint': [ 'flake8>=3.5.0', - 'flake8-import-order', - 'mypy>=0.770', + 'isort', + 'mypy>=0.800', 'docutils-stubs', ], 'test': [ 'pytest', 'pytest-cov', 'html5lib', - 'typed_ast', # for py35-37 + "typed_ast; python_version < '3.8'", 'cython', ], } @@ -76,9 +76,10 @@ class Tee: try: - from babel.messages.pofile import read_po - from babel.messages.frontend import compile_catalog from json import dump + + from babel.messages.frontend import compile_catalog + from babel.messages.pofile import read_po except ImportError: pass else: @@ -139,7 +140,7 @@ else: domain + '.js')) for js_file, (locale, po_file) in zip(js_files, po_files): - with open(po_file) as infile: + with open(po_file, encoding='utf8') as infile: catalog = read_po(infile, locale) if catalog.fuzzy and not self.use_fuzzy: @@ -157,13 +158,13 @@ else: msgid = msgid[0] jscatalog[msgid] = message.string - with open(js_file, 'wt') as outfile: + with open(js_file, 'wt', encoding='utf8') as outfile: outfile.write('Documentation.addTranslations(') dump({ 'messages': jscatalog, 'plural_expr': catalog.plural_expr, 'locale': str(catalog.locale) - }, outfile, sort_keys=True) + }, outfile, sort_keys=True, indent=4) outfile.write(');') cmdclass['compile_catalog'] = compile_catalog_plusjs @@ -203,6 +204,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Framework :: Setuptools Plugin', diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 8caea80d0..23a867fa0 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -4,7 +4,7 @@ The Sphinx documentation toolchain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -32,8 +32,8 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '3.1.0+' -__released__ = '3.1.0' # used when Sphinx builds its own docs +__version__ = '3.5.0+' +__released__ = '3.5.0' # used when Sphinx builds its own docs #: Version info for better programmatic use. #: @@ -43,7 +43,7 @@ __released__ = '3.1.0' # used when Sphinx builds its own docs #: #: .. versionadded:: 1.2 #: Before version 1.2, check the string ``sphinx.__version__``. -version_info = (3, 1, 0, 'beta', 0) +version_info = (3, 5, 0, 'beta', 0) package_dir = path.abspath(path.dirname(__file__)) diff --git a/sphinx/__main__.py b/sphinx/__main__.py index 5da409015..6192f52ae 100644 --- a/sphinx/__main__.py +++ b/sphinx/__main__.py @@ -4,7 +4,7 @@ The Sphinx documentation toolchain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 5e191e989..5f371e46b 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -4,7 +4,7 @@ Additional docutils nodes. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -21,6 +21,33 @@ if False: from sphinx.application import Sphinx +class document(nodes.document): + """The document root element patched by Sphinx. + + This fixes that document.set_id() does not support a node having multiple node Ids. + see https://sourceforge.net/p/docutils/patches/167/ + + .. important:: This is only for Sphinx internal use. Please don't use this + in your extensions. It will be removed without deprecation period. + """ + + def set_id(self, node: Element, msgnode: Element = None, + suggested_prefix: str = '') -> str: + from sphinx.util import docutils + if docutils.__version_info__ >= (0, 16): + ret = super().set_id(node, msgnode, suggested_prefix) # type: ignore + else: + ret = super().set_id(node, msgnode) + + if docutils.__version_info__ < (0, 17): + # register other node IDs forcedly + for node_id in node['ids']: + if node_id not in self.ids: + self.ids[node_id] = node + + return ret + + class translatable(nodes.Node): """Node which supports translation. diff --git a/sphinx/application.py b/sphinx/application.py index bd23c86e7..69887682f 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -6,7 +6,7 @@ Gracefully adapted from the TextPress system by Armin. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -18,16 +18,17 @@ import warnings from collections import deque from io import StringIO from os import path -from typing import Any, Callable, Dict, IO, List, Tuple, Union +from typing import IO, Any, Callable, Dict, List, Optional, Tuple, Union from docutils import nodes from docutils.nodes import Element, TextElement +from docutils.parsers import Parser from docutils.parsers.rst import Directive, roles from docutils.transforms import Transform from pygments.lexer import Lexer import sphinx -from sphinx import package_dir, locale +from sphinx import locale, package_dir from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.domains import Domain, Index @@ -42,9 +43,7 @@ from sphinx.project import Project from sphinx.registry import SphinxComponentRegistry from sphinx.roles import XRefRole from sphinx.theming import Theme -from sphinx.util import docutils -from sphinx.util import logging -from sphinx.util import progress_message +from sphinx.util import docutils, logging, progress_message from sphinx.util.build_phase import BuildPhase from sphinx.util.console import bold # type: ignore from sphinx.util.i18n import CatalogRepository @@ -55,8 +54,10 @@ from sphinx.util.typing import RoleFunction, TitleGetter if False: # For type annotation - from docutils.nodes import Node # NOQA from typing import Type # for python3.5.1 + + from docutils.nodes import Node # NOQA + from sphinx.builders import Builder @@ -134,7 +135,7 @@ class Sphinx: :ivar outdir: Directory for storing build documents. """ - def __init__(self, srcdir: str, confdir: str, outdir: str, doctreedir: str, + def __init__(self, srcdir: str, confdir: Optional[str], outdir: str, doctreedir: str, buildername: str, confoverrides: Dict = None, status: IO = sys.stdout, warning: IO = sys.stderr, freshenv: bool = False, warningiserror: bool = False, tags: List[str] = None, @@ -165,7 +166,7 @@ class Sphinx: if path.exists(self.outdir) and not path.isdir(self.outdir): raise ApplicationError(__('Output directory (%s) is not a directory') % - self.srcdir) + self.outdir) if self.srcdir == self.outdir: raise ApplicationError(__('Source directory and destination ' @@ -293,7 +294,10 @@ class Sphinx: if catalog.domain == 'sphinx' and catalog.is_outdated(): catalog.write_mo(self.config.language) - locale_dirs = [None, path.join(package_dir, 'locale')] + list(repo.locale_dirs) + locale_dirs = list(repo.locale_dirs) # type: List[Optional[str]] + locale_dirs += [None] + locale_dirs += [path.join(package_dir, 'locale')] + self.translator, has_translation = locale.init(locale_dirs, self.config.language) if has_translation or self.config.language == 'en': # "en" never needs to be translated @@ -400,9 +404,10 @@ class Sphinx: def require_sphinx(self, version: str) -> None: """Check the Sphinx version if requested. - Compare *version* (which must be a ``major.minor`` version string, e.g. - ``'1.1'``) with the version of the running Sphinx, and abort the build - when it is too old. + Compare *version* with the version of the running Sphinx, and abort the + build when it is too old. + + :param version: The required version in the form of ``major.minor``. .. versionadded:: 1.0 """ @@ -416,11 +421,11 @@ class Sphinx: For details on available core events and the arguments of callback functions, please see :ref:`events`. - Registered callbacks will be invoked on event in the order of *priority* and - registration. The priority is ascending order. - - The method returns a "listener ID" that can be used as an argument to - :meth:`disconnect`. + :param event: The name of target event + :param callback: Callback function for the event + :param priority: The priority of the callback. The callbacks will be invoked + in the order of *priority* in asending. + :return: A listener ID. It can be used for :meth:`disconnect`. .. versionchanged:: 3.0 @@ -432,7 +437,10 @@ class Sphinx: return listener_id def disconnect(self, listener_id: int) -> None: - """Unregister callback by *listener_id*.""" + """Unregister callback by *listener_id*. + + :param listener_id: A listener_id that :meth:`connect` returns + """ logger.debug('[app] disconnecting event: [id=%s]', listener_id) self.events.disconnect(listener_id) @@ -443,6 +451,10 @@ class Sphinx: Return the return values of all callbacks as a list. Do not emit core Sphinx events in extensions! + :param event: The name of event that will be emitted + :param args: The arguments for the event + :param allowed_exceptions: The list of exceptions that are allowed in the callbacks + .. versionchanged:: 3.1 Added *allowed_exceptions* to specify path-through exceptions @@ -455,6 +467,10 @@ class Sphinx: Return the result of the first callback that doesn't return ``None``. + :param event: The name of event that will be emitted + :param args: The arguments for the event + :param allowed_exceptions: The list of exceptions that are allowed in the callbacks + .. versionadded:: 0.5 .. versionchanged:: 3.1 @@ -468,8 +484,9 @@ class Sphinx: def add_builder(self, builder: "Type[Builder]", override: bool = False) -> None: """Register a new builder. - *builder* must be a class that inherits from - :class:`~sphinx.builders.Builder`. + :param builder: A builder class + :param override: If true, install the builder forcedly even if another builder + is already installed as the same name .. versionchanged:: 1.8 Add *override* keyword. @@ -493,6 +510,10 @@ class Sphinx: documents. * ``''`` if a change in the setting will not need any special rebuild. + The *types* value takes a list of types that describes the type of + configuration value. For example, ``[str]`` is used to describe a + configuration that takes string value. + .. versionchanged:: 0.6 Changed *rebuild* from a simple boolean (equivalent to ``''`` or ``'env'``) to a string. However, booleans are still accepted and @@ -526,6 +547,11 @@ class Sphinx: builtin translator. This allows extensions to use custom translator and define custom nodes for the translator (see :meth:`add_node`). + :param name: The name of builder for the translator + :param translator_class: A translator class + :param override: If true, install the translator forcedly even if another translator + is already installed as the same name + .. versionadded:: 1.3 .. versionchanged:: 1.8 Add *override* keyword. @@ -560,6 +586,9 @@ class Sphinx: Obviously, translators for which you don't specify visitor methods will choke on the node when encountered in a document to translate. + If *override* is True, the given *node* is forcedly installed even if + a node having the same name is already installed. + .. versionchanged:: 0.5 Added the support for keyword arguments giving visit functions. """ @@ -595,6 +624,9 @@ class Sphinx: Other keyword arguments are used for node visitor functions. See the :meth:`.Sphinx.add_node` for details. + If *override* is True, the given *node* is forcedly installed even if + a node having the same name is already installed. + .. versionadded:: 1.4 """ self.registry.add_enumerable_node(node, figtype, title_getter, override=override) @@ -603,19 +635,19 @@ class Sphinx: def add_directive(self, name: str, cls: "Type[Directive]", override: bool = False) -> None: """Register a Docutils directive. - *name* must be the prospective directive name. *cls* is a directive - class which inherits ``docutils.parsers.rst.Directive``. For more - details, see `the Docutils docs - <http://docutils.sourceforge.net/docs/howto/rst-directives.html>`_ . + :param name: The name of directive + :param cls: A directive class + :param override: If true, install the directive forcedly even if another directive + is already installed as the same name - For example, the (already existing) :rst:dir:`literalinclude` directive - would be added like this: + For example, a custom directive named ``my-directive`` would be added + like this: .. code-block:: python from docutils.parsers.rst import Directive, directives - class LiteralIncludeDirective(Directive): + class MyDirective(Directive): has_content = True required_arguments = 1 optional_arguments = 0 @@ -628,7 +660,11 @@ class Sphinx: def run(self): ... - add_directive('literalinclude', LiteralIncludeDirective) + def setup(app): + add_directive('my-directive', MyDirective) + + For more details, see `the Docutils docs + <http://docutils.sourceforge.net/docs/howto/rst-directives.html>`__ . .. versionchanged:: 0.6 Docutils 0.5-style directive classes are now supported. @@ -647,10 +683,13 @@ class Sphinx: def add_role(self, name: str, role: Any, override: bool = False) -> None: """Register a Docutils role. - *name* must be the role name that occurs in the source, *role* the role - function. Refer to the `Docutils documentation - <http://docutils.sourceforge.net/docs/howto/rst-roles.html>`_ for - more information. + :param name: The name of role + :param cls: A role function + :param override: If true, install the role forcedly even if another role is already + installed as the same name + + For more details about role functions, see `the Docutils docs + <http://docutils.sourceforge.net/docs/howto/rst-roles.html>`__ . .. versionchanged:: 1.8 Add *override* keyword. @@ -667,6 +706,9 @@ class Sphinx: Register a Docutils role that does nothing but wrap its contents in the node given by *nodeclass*. + If *override* is True, the given *nodeclass* is forcedly installed even if + a role named as *name* is already installed. + .. versionadded:: 0.6 .. versionchanged:: 1.8 Add *override* keyword. @@ -686,6 +728,9 @@ class Sphinx: Make the given *domain* (which must be a class; more precisely, a subclass of :class:`~sphinx.domains.Domain`) known to Sphinx. + If *override* is True, the given *domain* is forcedly installed even if + a domain having the same name is already installed. + .. versionadded:: 1.0 .. versionchanged:: 1.8 Add *override* keyword. @@ -699,6 +744,9 @@ class Sphinx: Like :meth:`add_directive`, but the directive is added to the domain named *domain*. + If *override* is True, the given *directive* is forcedly installed even if + a directive named as *name* is already installed. + .. versionadded:: 1.0 .. versionchanged:: 1.8 Add *override* keyword. @@ -712,6 +760,9 @@ class Sphinx: Like :meth:`add_role`, but the role is added to the domain named *domain*. + If *override* is True, the given *role* is forcedly installed even if + a role named as *name* is already installed. + .. versionadded:: 1.0 .. versionchanged:: 1.8 Add *override* keyword. @@ -725,6 +776,9 @@ class Sphinx: Add a custom *index* class to the domain named *domain*. *index* must be a subclass of :class:`~sphinx.domains.Index`. + If *override* is True, the given *index* is forcedly installed even if + an index having the same name is already installed. + .. versionadded:: 1.0 .. versionchanged:: 1.8 Add *override* keyword. @@ -788,6 +842,9 @@ class Sphinx: For the role content, you have the same syntactical possibilities as for standard Sphinx roles (see :ref:`xref-syntax`). + If *override* is True, the given object_type is forcedly installed even if + an object_type having the same name is already installed. + .. versionchanged:: 1.8 Add *override* keyword. """ @@ -824,6 +881,9 @@ class Sphinx: (Of course, the element following the ``topic`` directive needn't be a section.) + If *override* is True, the given crossref_type is forcedly installed even if + a crossref_type having the same name is already installed. + .. versionchanged:: 1.8 Add *override* keyword. """ @@ -873,22 +933,24 @@ class Sphinx: """ self.registry.add_post_transform(transform) - def add_javascript(self, filename: str, **kwargs: str) -> None: + def add_javascript(self, filename: str, **kwargs: Any) -> None: """An alias of :meth:`add_js_file`.""" warnings.warn('The app.add_javascript() is deprecated. ' 'Please use app.add_js_file() instead.', RemovedInSphinx40Warning, stacklevel=2) self.add_js_file(filename, **kwargs) - def add_js_file(self, filename: str, **kwargs: str) -> None: + def add_js_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None: """Register a JavaScript file to include in the HTML output. Add *filename* to the list of JavaScript files that the default HTML - template will include. The filename must be relative to the HTML - static path , or a full URI with scheme. If the keyword argument - ``body`` is given, its value will be added between the - ``<script>`` tags. Extra keyword arguments are included as - attributes of the ``<script>`` tag. + template will include in order of *priority* (ascending). The filename + must be relative to the HTML static path , or a full URI with scheme. + If the priority of JavaScript file is the same as others, the JavaScript + files will be included in order of the registration. If the keyword + argument ``body`` is given, its value will be added between the + ``<script>`` tags. Extra keyword arguments are included as attributes of + the ``<script>`` tag. Example:: @@ -901,23 +963,43 @@ class Sphinx: app.add_js_file(None, body="var myVariable = 'foo';") # => <script>var myVariable = 'foo';</script> + .. list-table:: priority range for JavaScript files + :widths: 20,80 + + * - Priority + - Main purpose in Sphinx + * - 200 + - default priority for built-in JavaScript files + * - 500 + - default priority for extensions + * - 800 + - default priority for :confval:`html_js_files` + + A JavaScript file can be added to the specific HTML page when on extension + calls this method on :event:`html-page-context` event. + .. versionadded:: 0.5 .. versionchanged:: 1.8 Renamed from ``app.add_javascript()``. And it allows keyword arguments as attributes of script tag. + + .. versionchanged:: 3.5 + Take priority argument. Allow to add a JavaScript file to the specific page. """ - self.registry.add_js_file(filename, **kwargs) + self.registry.add_js_file(filename, priority=priority, **kwargs) if hasattr(self.builder, 'add_js_file'): - self.builder.add_js_file(filename, **kwargs) # type: ignore + self.builder.add_js_file(filename, priority=priority, **kwargs) # type: ignore - def add_css_file(self, filename: str, **kwargs: str) -> None: + def add_css_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None: """Register a stylesheet to include in the HTML output. Add *filename* to the list of CSS files that the default HTML template - will include. The filename must be relative to the HTML static path, - or a full URI with scheme. The keyword arguments are also accepted for - attributes of ``<link>`` tag. + will include in order of *priority* (ascending). The filename must be + relative to the HTML static path, or a full URI with scheme. If the + priority of CSS file is the same as others, the CSS files will be + included in order of the registration. The keyword arguments are also + accepted for attributes of ``<link>`` tag. Example:: @@ -932,6 +1014,19 @@ class Sphinx: # => <link rel="alternate stylesheet" href="_static/fancy.css" # type="text/css" title="fancy" /> + .. list-table:: priority range for CSS files + :widths: 20,80 + + * - Priority + - Main purpose in Sphinx + * - 500 + - default priority for extensions + * - 800 + - default priority for :confval:`html_css_files` + + A CSS file can be added to the specific HTML page when on extension calls + this method on :event:`html-page-context` event. + .. versionadded:: 1.0 .. versionchanged:: 1.6 @@ -944,11 +1039,14 @@ class Sphinx: .. versionchanged:: 1.8 Renamed from ``app.add_stylesheet()``. And it allows keyword arguments as attributes of link tag. + + .. versionchanged:: 3.5 + Take priority argument. Allow to add a CSS file to the specific page. """ logger.debug('[app] adding stylesheet: %r', filename) - self.registry.add_css_files(filename, **kwargs) + self.registry.add_css_files(filename, priority=priority, **kwargs) if hasattr(self.builder, 'add_css_file'): - self.builder.add_css_file(filename, **kwargs) # type: ignore + self.builder.add_css_file(filename, priority=priority, **kwargs) # type: ignore def add_stylesheet(self, filename: str, alternate: bool = False, title: str = None ) -> None: @@ -957,7 +1055,7 @@ class Sphinx: 'Please use app.add_css_file() instead.', RemovedInSphinx40Warning, stacklevel=2) - attributes = {} # type: Dict[str, str] + attributes = {} # type: Dict[str, Any] if alternate: attributes['rel'] = 'alternate stylesheet' else: @@ -1004,7 +1102,7 @@ class Sphinx: logger.debug('[app] adding lexer: %r', (alias, lexer)) if isinstance(lexer, Lexer): warnings.warn('app.add_lexer() API changed; ' - 'Please give lexer class instead instance', + 'Please give lexer class instead of instance', RemovedInSphinx40Warning, stacklevel=2) lexers[alias] = lexer else: @@ -1019,6 +1117,9 @@ class Sphinx: new types of objects. See the source of the autodoc module for examples on how to subclass :class:`Documenter`. + 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 .. versionadded:: 0.6 @@ -1057,7 +1158,7 @@ class Sphinx: .. versionadded:: 1.1 """ logger.debug('[app] adding search language: %r', cls) - from sphinx.search import languages, SearchLanguage + from sphinx.search import SearchLanguage, languages assert issubclass(cls, SearchLanguage) languages[cls.lang] = cls @@ -1067,13 +1168,19 @@ class Sphinx: Same as :confval:`source_suffix`. The users can override this using the setting. + If *override* is True, the given *suffix* is forcedly installed even if + a same suffix is already installed. + .. versionadded:: 1.8 """ self.registry.add_source_suffix(suffix, filetype, override=override) - def add_source_parser(self, *args: Any, **kwargs: Any) -> None: + def add_source_parser(self, parser: "Type[Parser]", override: bool = False) -> None: """Register a parser class. + If *override* is True, the given *parser* is forcedly installed even if + a parser for the same suffix is already installed. + .. versionadded:: 1.4 .. versionchanged:: 1.8 *suffix* argument is deprecated. It only accepts *parser* argument. @@ -1081,7 +1188,7 @@ class Sphinx: .. versionchanged:: 1.8 Add *override* keyword. """ - self.registry.add_source_parser(*args, **kwargs) + self.registry.add_source_parser(parser, override=override) def add_env_collector(self, collector: "Type[EnvironmentCollector]") -> None: """Register an environment collector class. diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 93c246c69..58030bb6c 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -4,7 +4,7 @@ Builder superclass for all builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -17,26 +17,24 @@ from docutils import nodes from docutils.nodes import Node from sphinx.config import Config -from sphinx.environment import BuildEnvironment, CONFIG_OK, CONFIG_CHANGED_REASON +from sphinx.environment import CONFIG_CHANGED_REASON, CONFIG_OK, BuildEnvironment from sphinx.environment.adapters.asset import ImageAdapter from sphinx.errors import SphinxError from sphinx.events import EventManager from sphinx.io import read_doc from sphinx.locale import __ -from sphinx.util import import_object, logging, rst, progress_message, status_iterator +from sphinx.util import import_object, logging, progress_message, rst, status_iterator from sphinx.util.build_phase import BuildPhase from sphinx.util.console import bold # type: ignore from sphinx.util.docutils import sphinx_domains from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath -from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \ - parallel_available +from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, parallel_available from sphinx.util.tags import Tags # side effect: registers roles and directives -from sphinx import roles # noqa -from sphinx import directives # noqa - +from sphinx import directives # NOQA isort:skip +from sphinx import roles # NOQA isort:skip try: import multiprocessing except ImportError: @@ -45,6 +43,7 @@ except ImportError: if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index f26a1ba9f..7df3f8df5 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -4,7 +4,7 @@ Base class of epub2/epub3 builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -25,11 +25,10 @@ from sphinx import addnodes from sphinx.builders.html import BuildInfo, StandaloneHTMLBuilder from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.locale import __ -from sphinx.util import logging -from sphinx.util import status_iterator +from sphinx.util import logging, status_iterator from sphinx.util.fileutil import copy_asset_file from sphinx.util.i18n import format_date -from sphinx.util.osutil import ensuredir, copyfile +from sphinx.util.osutil import copyfile, ensuredir try: from PIL import Image @@ -208,7 +207,12 @@ class EpubBuilder(StandaloneHTMLBuilder): appeared = set() # type: Set[str] for node in nodes: if node['refuri'] in appeared: - logger.warning(__('duplicated ToC entry found: %s'), node['refuri']) + logger.warning( + __('duplicated ToC entry found: %s'), + node['refuri'], + type="epub", + subtype="duplicated_toc_entry", + ) else: appeared.add(node['refuri']) @@ -388,7 +392,7 @@ class EpubBuilder(StandaloneHTMLBuilder): return ext in VECTOR_GRAPHICS_EXTENSIONS def copy_image_files_pil(self) -> None: - """Copy images using Pillow, the Python Imaging Libary. + """Copy images using Pillow, the Python Imaging Library. The method tries to read and write the files with Pillow, converting the format and resizing the image if necessary/possible. """ diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py index 759ba66da..bfc8c8dc8 100644 --- a/sphinx/builders/applehelp.py +++ b/sphinx/builders/applehelp.py @@ -4,30 +4,33 @@ Build Apple help books. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import warnings from typing import Any, Dict -from sphinxcontrib.applehelp import ( - AppleHelpCodeSigningFailed, - AppleHelpIndexerFailed, - AppleHelpBuilder, -) +from sphinxcontrib.applehelp import (AppleHelpBuilder, AppleHelpCodeSigningFailed, + AppleHelpIndexerFailed) from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias - deprecated_alias('sphinx.builders.applehelp', { 'AppleHelpCodeSigningFailed': AppleHelpCodeSigningFailed, 'AppleHelpIndexerFailed': AppleHelpIndexerFailed, 'AppleHelpBuilder': AppleHelpBuilder, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'AppleHelpCodeSigningFailed': + 'sphinxcontrib.applehelp.AppleHelpCodeSigningFailed', + 'AppleHelpIndexerFailed': + 'sphinxcontrib.applehelp.AppleHelpIndexerFailed', + 'AppleHelpBuilder': 'sphinxcontrib.applehelp.AppleHelpBuilder', + }) def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index 7cf9d098b..87dd03fb8 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -4,14 +4,13 @@ Changelog builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import html from os import path -from typing import Any, Dict, List, Tuple -from typing import cast +from typing import Any, Dict, List, Tuple, cast from sphinx import package_dir from sphinx.application import Sphinx @@ -24,7 +23,6 @@ from sphinx.util.console import bold # type: ignore from sphinx.util.fileutil import copy_asset_file from sphinx.util.osutil import ensuredir, os_path - logger = logging.getLogger(__name__) diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py index dda7c411f..9625b62f4 100644 --- a/sphinx/builders/devhelp.py +++ b/sphinx/builders/devhelp.py @@ -6,7 +6,7 @@ .. _Devhelp: https://wiki.gnome.org/Apps/Devhelp - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -18,12 +18,14 @@ from sphinxcontrib.devhelp import DevhelpBuilder from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias - deprecated_alias('sphinx.builders.devhelp', { 'DevhelpBuilder': DevhelpBuilder, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'DevhelpBuilder': 'sphinxcontrib.devhelp.DevhelpBuilder' + }) def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/builders/dirhtml.py b/sphinx/builders/dirhtml.py index ba60c923c..5e6b17259 100644 --- a/sphinx/builders/dirhtml.py +++ b/sphinx/builders/dirhtml.py @@ -4,7 +4,7 @@ Directory HTML builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -49,9 +49,12 @@ class DirectoryHTMLBuilder(StandaloneHTMLBuilder): # for compatibility deprecated_alias('sphinx.builders.html', { - 'DirectoryHTMLBuilder': DirectoryHTMLBuilder, + 'DirectoryHTMLBuilder': DirectoryHTMLBuilder, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'DirectoryHTMLBuilder': 'sphinx.builders.dirhtml.DirectoryHTMLBuilder', + }) def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/builders/dummy.py b/sphinx/builders/dummy.py index 33d2506ac..722e70d1c 100644 --- a/sphinx/builders/dummy.py +++ b/sphinx/builders/dummy.py @@ -4,7 +4,7 @@ Do syntax checks, but no writing. - :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index cf795f3ba..d1cf64eb3 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -5,7 +5,7 @@ Build epub3 files. Originally derived from epub.py. - :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -18,7 +18,7 @@ from typing import Any, Dict, List, Set, Tuple from sphinx import package_dir from sphinx.application import Sphinx from sphinx.builders import _epub_base -from sphinx.config import Config, ENUM +from sphinx.config import ENUM, Config from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.locale import __ from sphinx.util import logging, xmlname_checker diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py index 65f112510..75c95c0bc 100644 --- a/sphinx/builders/gettext.py +++ b/sphinx/builders/gettext.py @@ -4,33 +4,32 @@ The MessageCatalogBuilder class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from codecs import open -from collections import defaultdict, OrderedDict -from datetime import datetime, tzinfo, timedelta -from os import path, walk, getenv +from collections import OrderedDict, defaultdict +from datetime import datetime, timedelta, tzinfo +from os import getenv, path, walk from time import time -from typing import Any, Dict, Iterable, Generator, List, Set, Tuple, Union +from typing import Any, Dict, Generator, Iterable, List, Set, Tuple, Union from uuid import uuid4 from docutils import nodes from docutils.nodes import Element -from sphinx import addnodes -from sphinx import package_dir +from sphinx import addnodes, package_dir from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.domains.python import pairindextypes from sphinx.errors import ThemeError from sphinx.locale import __ -from sphinx.util import split_index_msg, logging, status_iterator +from sphinx.util import logging, split_index_msg, status_iterator from sphinx.util.console import bold # type: ignore from sphinx.util.i18n import CatalogInfo, docname_to_domain from sphinx.util.nodes import extract_messages, traverse_translatable_index -from sphinx.util.osutil import ensuredir, canon_path, relpath +from sphinx.util.osutil import canon_path, ensuredir, relpath from sphinx.util.tags import Tags from sphinx.util.template import SphinxRenderer @@ -278,7 +277,7 @@ class MessageCatalogBuilder(I18nBuilder): origin = MsgOrigin(template, line) self.catalogs['sphinx'].add(msg, origin) except Exception as exc: - raise ThemeError('%s: %r' % (template, exc)) + raise ThemeError('%s: %r' % (template, exc)) from exc def build(self, docnames: Iterable[str], summary: str = None, method: str = 'update') -> None: # NOQA self._extract_from_template() @@ -316,7 +315,7 @@ class MessageCatalogBuilder(I18nBuilder): def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(MessageCatalogBuilder) - app.add_config_value('gettext_compact', True, 'gettext') + app.add_config_value('gettext_compact', True, 'gettext', {bool, str}) app.add_config_value('gettext_location', True, 'gettext') app.add_config_value('gettext_uuid', False, 'gettext') app.add_config_value('gettext_auto_build', True, 'env') diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py index 5340c93f9..f5152f6da 100644 --- a/sphinx/builders/html/__init__.py +++ b/sphinx/builders/html/__init__.py @@ -4,17 +4,19 @@ Several HTML builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import html +import os import posixpath import re import sys import warnings from os import path -from typing import Any, Dict, IO, Iterable, Iterator, List, Set, Tuple +from typing import IO, Any, Dict, Iterable, Iterator, List, Set, Tuple +from urllib.parse import quote from docutils import nodes from docutils.core import publish_parts @@ -23,10 +25,10 @@ from docutils.io import DocTreeInput, StringOutput from docutils.nodes import Node from docutils.utils import relative_path -from sphinx import package_dir, __display_version__ +from sphinx import __display_version__, package_dir from sphinx.application import Sphinx from sphinx.builders import Builder -from sphinx.config import Config +from sphinx.config import ENUM, Config from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.domains import Domain, Index, IndexEntry from sphinx.environment.adapters.asset import ImageAdapter @@ -37,15 +39,15 @@ from sphinx.highlighting import PygmentsBridge from sphinx.locale import _, __ from sphinx.search import js_index from sphinx.theming import HTMLThemeFactory -from sphinx.util import logging, progress_message, status_iterator, md5 +from sphinx.util import logging, md5, progress_message, status_iterator from sphinx.util.docutils import is_html5_writer_available, new_document from sphinx.util.fileutil import copy_asset from sphinx.util.i18n import format_date from sphinx.util.inventory import InventoryFile -from sphinx.util.matching import patmatch, Matcher, DOTFILES -from sphinx.util.osutil import os_path, relative_uri, ensuredir, movefile, copyfile +from sphinx.util.matching import DOTFILES, Matcher, patmatch +from sphinx.util.osutil import copyfile, ensuredir, os_path, relative_uri from sphinx.util.tags import Tags -from sphinx.writers.html import HTMLWriter, HTMLTranslator +from sphinx.writers.html import HTMLTranslator, HTMLWriter if False: # For type annotation @@ -88,10 +90,13 @@ class Stylesheet(str): attributes = None # type: Dict[str, str] filename = None # type: str + priority = None # type: int - def __new__(cls, filename: str, *args: str, **attributes: str) -> "Stylesheet": - self = str.__new__(cls, filename) # type: ignore + def __new__(cls, filename: str, *args: str, priority: int = 500, **attributes: Any + ) -> "Stylesheet": + self = str.__new__(cls, filename) self.filename = filename + self.priority = priority self.attributes = attributes self.attributes.setdefault('rel', 'stylesheet') self.attributes.setdefault('type', 'text/css') @@ -111,10 +116,12 @@ class JavaScript(str): attributes = None # type: Dict[str, str] filename = None # type: str + priority = None # type: int - def __new__(cls, filename: str, **attributes: str) -> "JavaScript": - self = str.__new__(cls, filename) # type: ignore + def __new__(cls, filename: str, priority: int = 500, **attributes: str) -> "JavaScript": + self = str.__new__(cls, filename) self.filename = filename + self.priority = priority self.attributes = attributes return self @@ -140,7 +147,7 @@ class BuildInfo: build_info.tags_hash = lines[3].split()[1].strip() return build_info except Exception as exc: - raise ValueError(__('build info file is broken: %r') % exc) + raise ValueError(__('build info file is broken: %r') % exc) from exc def __init__(self, config: Config = None, tags: Tags = None, config_categories: List[str] = []) -> None: # NOQA self.config_hash = '' @@ -288,30 +295,31 @@ class StandaloneHTMLBuilder(Builder): self.add_css_file(filename, **attrs) for filename, attrs in self.get_builder_config('css_files', 'html'): + attrs.setdefault('priority', 800) # User's CSSs are loaded after extensions' self.add_css_file(filename, **attrs) - def add_css_file(self, filename: str, **kwargs: str) -> None: + def add_css_file(self, filename: str, **kwargs: Any) -> None: if '://' not in filename: filename = posixpath.join('_static', filename) self.css_files.append(Stylesheet(filename, **kwargs)) # type: ignore def init_js_files(self) -> None: - self.add_js_file('jquery.js') - self.add_js_file('underscore.js') - self.add_js_file('doctools.js') - self.add_js_file('language_data.js') + self.add_js_file('jquery.js', priority=200) + self.add_js_file('underscore.js', priority=200) + self.add_js_file('doctools.js', priority=200) for filename, attrs in self.app.registry.js_files: self.add_js_file(filename, **attrs) for filename, attrs in self.get_builder_config('js_files', 'html'): + attrs.setdefault('priority', 800) # User's JSs are loaded after extensions' self.add_js_file(filename, **attrs) if self.config.language and self._get_translations_js(): self.add_js_file('translations.js') - def add_js_file(self, filename: str, **kwargs: str) -> None: + def add_js_file(self, filename: str, **kwargs: Any) -> None: if filename and '://' not in filename: filename = posixpath.join('_static', filename) @@ -447,9 +455,6 @@ class StandaloneHTMLBuilder(Builder): logo = path.basename(self.config.html_logo) if self.config.html_logo else '' favicon = path.basename(self.config.html_favicon) if self.config.html_favicon else '' - if not isinstance(self.config.html_use_opensearch, str): - logger.warning(__('html_use_opensearch config value must now be a string')) - self.relations = self.env.collect_relations() rellinks = [] # type: List[Tuple[str, str, str, str]] @@ -461,6 +466,10 @@ class StandaloneHTMLBuilder(Builder): rellinks.append((indexname, indexcls.localname, '', indexcls.shortname)) + # back up script_files and css_files to allow adding JS/CSS files to a specific page. + self._script_files = list(self.script_files) + self._css_files = list(self.css_files) + if self.config.html_style is not None: stylename = self.config.html_style elif self.theme: @@ -640,17 +649,17 @@ class StandaloneHTMLBuilder(Builder): def gen_additional_pages(self) -> None: # additional pages from conf.py for pagename, template in self.config.html_additional_pages.items(): - logger.info(' ' + pagename, nonl=True) + logger.info(pagename + ' ', nonl=True) self.handle_page(pagename, {}, template) # the search page if self.search: - logger.info(' search', nonl=True) + logger.info('search ', nonl=True) self.handle_page('search', {}, 'search.html') # the opensearch xml file if self.config.html_use_opensearch and self.search: - logger.info(' opensearch', nonl=True) + logger.info('opensearch ', nonl=True) fn = path.join(self.outdir, '_static', 'opensearch.xml') self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn) @@ -668,7 +677,7 @@ class StandaloneHTMLBuilder(Builder): 'genindexcounts': indexcounts, 'split_index': self.config.html_split_index, } - logger.info(' genindex', nonl=True) + logger.info('genindex ', nonl=True) if self.config.html_split_index: self.handle_page('genindex', genindexcontext, @@ -690,7 +699,7 @@ class StandaloneHTMLBuilder(Builder): 'content': content, 'collapse_index': collapse, } - logger.info(' ' + indexname, nonl=True) + logger.info(indexname + ' ', nonl=True) self.handle_page(indexname, indexcontext, 'domainindex.html') def copy_image_files(self) -> None: @@ -750,18 +759,27 @@ class StandaloneHTMLBuilder(Builder): copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js')) def copy_theme_static_files(self, context: Dict) -> None: + def onerror(filename: str, error: Exception) -> None: + logger.warning(__('Failed to copy a file in html_static_file: %s: %r'), + filename, error) + if self.theme: for entry in self.theme.get_theme_dirs()[::-1]: copy_asset(path.join(entry, 'static'), path.join(self.outdir, '_static'), - excluded=DOTFILES, context=context, renderer=self.templates) + excluded=DOTFILES, context=context, + renderer=self.templates, onerror=onerror) def copy_html_static_files(self, context: Dict) -> None: + def onerror(filename: str, error: Exception) -> None: + logger.warning(__('Failed to copy a file in html_static_file: %s: %r'), + filename, error) + excluded = Matcher(self.config.exclude_patterns + ["**/.*"]) for entry in self.config.html_static_path: copy_asset(path.join(self.confdir, entry), path.join(self.outdir, '_static'), - excluded, context=context, renderer=self.templates) + excluded, context=context, renderer=self.templates, onerror=onerror) def copy_html_logo(self) -> None: if self.config.html_logo: @@ -775,7 +793,7 @@ class StandaloneHTMLBuilder(Builder): def copy_static_files(self) -> None: try: - with progress_message(__('copying static files... ')): + with progress_message(__('copying static files')): ensuredir(path.join(self.outdir, '_static')) # prepare context for templates @@ -886,6 +904,8 @@ class StandaloneHTMLBuilder(Builder): def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str: if 'includehidden' not in kwargs: kwargs['includehidden'] = False + if kwargs.get('maxdepth') == '': + kwargs.pop('maxdepth') return self.render_partial(TocTree(self.env).get_toctree_for( docname, self, collapse, **kwargs))['fragment'] @@ -945,7 +965,7 @@ class StandaloneHTMLBuilder(Builder): # --------- these are overwritten by the serialization builder def get_target_uri(self, docname: str, typ: str = None) -> str: - return docname + self.link_suffix + return quote(docname) + self.link_suffix def handle_page(self, pagename: str, addctx: Dict, templatename: str = 'page.html', outfilename: str = None, event_arg: Any = None) -> None: @@ -1000,12 +1020,20 @@ class StandaloneHTMLBuilder(Builder): self.add_sidebars(pagename, ctx) ctx.update(addctx) + # revert script_files and css_files + self.script_files[:] = self._script_files + self.css_files[:] = self.css_files + self.update_page_context(pagename, templatename, ctx, event_arg) newtmpl = self.app.emit_firstresult('html-page-context', pagename, templatename, ctx, event_arg) if newtmpl: templatename = newtmpl + # sort JS/CSS before rendering HTML + ctx['script_files'].sort(key=lambda js: js.priority) + ctx['css_files'].sort(key=lambda js: js.priority) + try: output = self.templates.render(templatename, ctx) except UnicodeError: @@ -1015,7 +1043,7 @@ class StandaloneHTMLBuilder(Builder): return except Exception as exc: raise ThemeError(__("An error happened in rendering the page %s.\nReason: %r") % - (pagename, exc)) + (pagename, exc)) from exc if not outfilename: outfilename = self.get_outfilename(pagename) @@ -1059,7 +1087,7 @@ class StandaloneHTMLBuilder(Builder): else: with open(searchindexfn + '.tmp', 'wb') as fb: self.indexer.dump(fb, self.indexer_format) - movefile(searchindexfn + '.tmp', searchindexfn) + os.replace(searchindexfn + '.tmp', searchindexfn) def convert_html_css_files(app: Sphinx, config: Config) -> None: @@ -1177,10 +1205,21 @@ def validate_html_favicon(app: Sphinx, config: Config) -> None: config.html_favicon = None # type: ignore +def migrate_html_add_permalinks(app: Sphinx, config: Config) -> None: + """Migrate html_add_permalinks to html_permalinks*.""" + if config.html_add_permalinks: + 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 + + # for compatibility +import sphinxcontrib.serializinghtml # NOQA + import sphinx.builders.dirhtml # NOQA import sphinx.builders.singlehtml # NOQA -import sphinxcontrib.serializinghtml # NOQA def setup(app: Sphinx) -> Dict[str, Any]: @@ -1206,7 +1245,9 @@ 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', '¶', 'html') + app.add_config_value('html_add_permalinks', None, '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') app.add_config_value('html_split_index', False, 'html') app.add_config_value('html_copy_source', True, 'html') @@ -1226,12 +1267,19 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('html_search_scorer', '', None) app.add_config_value('html_scaled_image_link', True, 'html') app.add_config_value('html_baseurl', '', 'html') + app.add_config_value('html_codeblock_linenos_style', 'table', 'html', + ENUM('table', 'inline')) app.add_config_value('html_math_renderer', None, 'env') app.add_config_value('html4_writer', False, 'html') + # events + app.add_event('html-collect-pages') + app.add_event('html-page-context') + # event handlers app.connect('config-inited', convert_html_css_files, priority=800) app.connect('config-inited', convert_html_js_files, priority=800) + app.connect('config-inited', migrate_html_add_permalinks, priority=800) app.connect('config-inited', validate_html_extra_path, priority=800) app.connect('config-inited', validate_html_static_path, priority=800) app.connect('config-inited', validate_html_logo, priority=800) diff --git a/sphinx/builders/html/transforms.py b/sphinx/builders/html/transforms.py index c91da57e9..cb9af5f28 100644 --- a/sphinx/builders/html/transforms.py +++ b/sphinx/builders/html/transforms.py @@ -4,12 +4,12 @@ Transforms for HTML builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re -from typing import Any, Dict +from typing import Any, Dict, List from docutils import nodes @@ -28,7 +28,7 @@ class KeyboardTransform(SphinxPostTransform): After:: - <literal class="kbd"> + <literal class="kbd compound"> <literal class="kbd"> Control - @@ -37,18 +37,30 @@ class KeyboardTransform(SphinxPostTransform): """ default_priority = 400 builders = ('html',) - pattern = re.compile(r'(-|\+|\^|\s+)') + pattern = re.compile(r'(?<=.)(-|\+|\^|\s+)(?=.)') + multiwords_keys = (('caps', 'lock'), + ('page' 'down'), + ('page', 'up'), + ('scroll' 'lock'), + ('num', 'lock'), + ('sys' 'rq'), + ('back' 'space')) def run(self, **kwargs: Any) -> None: matcher = NodeMatcher(nodes.literal, classes=["kbd"]) for node in self.document.traverse(matcher): # type: nodes.literal parts = self.pattern.split(node[-1].astext()) - if len(parts) == 1: + if len(parts) == 1 or self.is_multiwords_key(parts): continue + node['classes'].append('compound') node.pop() while parts: - key = parts.pop(0) + if self.is_multiwords_key(parts): + key = ''.join(parts[:3]) + parts[:3] = [] + else: + key = parts.pop(0) node += nodes.literal('', key, classes=["kbd"]) try: @@ -58,6 +70,16 @@ class KeyboardTransform(SphinxPostTransform): except IndexError: pass + def is_multiwords_key(self, parts: List[str]) -> bool: + if len(parts) >= 3 and parts[1].strip() == '': + name = parts[0].lower(), parts[2].lower() + if name in self.multiwords_keys: + return True + else: + return False + else: + return False + def setup(app: Sphinx) -> Dict[str, Any]: app.add_post_transform(KeyboardTransform) diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index 1d6304d38..08719712c 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -5,29 +5,34 @@ Build HTML help support files. Parts adapted from Python's Doc/tools/prechm.py. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import warnings from typing import Any, Dict -from sphinxcontrib.htmlhelp import ( - chm_locales, chm_htmlescape, HTMLHelpBuilder, default_htmlhelp_basename -) +from sphinxcontrib.htmlhelp import (HTMLHelpBuilder, chm_htmlescape, chm_locales, + default_htmlhelp_basename) from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias - deprecated_alias('sphinx.builders.htmlhelp', { 'chm_locales': chm_locales, 'chm_htmlescape': chm_htmlescape, - 'HTMLHelpBuilder': HTMLHelpBuilder, + 'HTMLHelpBuilder': HTMLHelpBuilder, 'default_htmlhelp_basename': default_htmlhelp_basename, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'chm_locales': 'sphinxcontrib.htmlhelp.chm_locales', + 'chm_htmlescape': 'sphinxcontrib.htmlhelp.chm_htmlescape', + 'HTMLHelpBuilder': 'sphinxcontrib.htmlhelp.HTMLHelpBuilder', + 'default_htmlhelp_basename': + 'sphinxcontrib.htmlhelp.default_htmlhelp_basename', + }) def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index 88c471675..5c7a7412a 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -4,7 +4,7 @@ LaTeX builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -17,18 +17,18 @@ from docutils.frontend import OptionParser from docutils.nodes import Node import sphinx.builders.latex.nodes # NOQA # Workaround: import this before writer to avoid ImportError -from sphinx import package_dir, addnodes, highlighting +from sphinx import addnodes, highlighting, package_dir from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.builders.latex.constants import ADDITIONAL_SETTINGS, DEFAULT_SETTINGS, SHORTHANDOFF from sphinx.builders.latex.theming import Theme, ThemeFactory from sphinx.builders.latex.util import ExtBabel -from sphinx.config import Config, ENUM -from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.config import ENUM, Config +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.environment.adapters.asset import ImageAdapter from sphinx.errors import NoUri, SphinxError from sphinx.locale import _, __ -from sphinx.util import texescape, logging, progress_message, status_iterator +from sphinx.util import logging, progress_message, status_iterator, texescape from sphinx.util.console import bold, darkgreen # type: ignore from sphinx.util.docutils import SphinxFileOutput, new_document from sphinx.util.fileutil import copy_asset_file @@ -36,11 +36,10 @@ from sphinx.util.i18n import format_date from sphinx.util.nodes import inline_all_toctrees from sphinx.util.osutil import SEP, make_filename_from_project from sphinx.util.template import LaTeXRenderer -from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator +from sphinx.writers.latex import LaTeXTranslator, LaTeXWriter # load docutils.nodes after loading sphinx.builders.latex.nodes -from docutils import nodes # NOQA - +from docutils import nodes # isort:skip XINDY_LANG_OPTIONS = { # language codes from docutils.writers.latex2e.Babel @@ -128,8 +127,6 @@ class LaTeXBuilder(Builder): self.docnames = [] # type: Iterable[str] self.document_data = [] # type: List[Tuple[str, str, str, str, str, bool]] self.themes = ThemeFactory(self.app) - self.usepackages = self.app.registry.latex_packages - self.usepackages_after_hyperref = self.app.registry.latex_packages_after_hyperref texescape.init() self.init_context() @@ -179,10 +176,6 @@ class LaTeXBuilder(Builder): key = (self.config.latex_engine, self.config.language[:2]) self.context.update(ADDITIONAL_SETTINGS.get(key, {})) - # Apply extension settings to context - self.context['packages'] = self.usepackages - self.context['packages_after_hyperref'] = self.usepackages_after_hyperref - # Apply user settings to context self.context.update(self.config.latex_elements) self.context['release'] = self.config.release @@ -203,6 +196,13 @@ class LaTeXBuilder(Builder): # Show the release label only if release value exists self.context.setdefault('releasename', _('Release')) + def update_context(self) -> None: + """Update template variables for .tex file just before writing.""" + # Apply extension settings to context + registry = self.app.registry + self.context['packages'] = registry.latex_packages + self.context['packages_after_hyperref'] = registry.latex_packages_after_hyperref + def init_babel(self) -> None: self.babel = ExtBabel(self.config.language, not self.context['babel']) if self.config.language and not self.babel.is_supported_language(): @@ -290,6 +290,7 @@ class LaTeXBuilder(Builder): doctree['tocdepth'] = tocdepth self.post_process_images(doctree) self.update_doc_context(title, author, theme) + self.update_context() with progress_message(__("writing")): docsettings._author = author @@ -448,6 +449,18 @@ class LaTeXBuilder(Builder): filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty_t') copy_asset_file(filename, self.outdir, context=context, renderer=LaTeXRenderer()) + @property + def usepackages(self) -> List[Tuple[str, str]]: + warnings.warn('LaTeXBuilder.usepackages is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + return self.app.registry.latex_packages + + @property + def usepackages_after_hyperref(self) -> List[Tuple[str, str]]: + warnings.warn('LaTeXBuilder.usepackages_after_hyperref is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + return self.app.registry.latex_packages_after_hyperref + def patch_settings(settings: Any) -> Any: """Make settings object to show deprecation messages.""" @@ -503,9 +516,9 @@ def validate_latex_theme_options(app: Sphinx, config: Config) -> None: config.latex_theme_options.pop(key) -def install_pakcages_for_ja(app: Sphinx) -> None: +def install_packages_for_ja(app: Sphinx) -> None: """Install packages for Japanese.""" - if app.config.language == 'ja': + if app.config.language == 'ja' and app.config.latex_engine in ('platex', 'uplatex'): app.add_latex_package('pxjahyper', after_hyperref=True) @@ -556,7 +569,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(LaTeXBuilder) app.connect('config-inited', validate_config_values, priority=800) app.connect('config-inited', validate_latex_theme_options, priority=800) - app.connect('builder-inited', install_pakcages_for_ja) + app.connect('builder-inited', install_packages_for_ja) app.add_config_value('latex_engine', default_latex_engine, None, ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex')) diff --git a/sphinx/builders/latex/constants.py b/sphinx/builders/latex/constants.py index 7146079ff..0b20c7cef 100644 --- a/sphinx/builders/latex/constants.py +++ b/sphinx/builders/latex/constants.py @@ -4,13 +4,12 @@ consntants for LaTeX builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from typing import Any, Dict - PDFLATEX_DEFAULT_FONTPKG = r''' \usepackage{times} \expandafter\ifx\csname T@LGR\endcsname\relax diff --git a/sphinx/builders/latex/nodes.py b/sphinx/builders/latex/nodes.py index e6b1e5aee..eaed6b862 100644 --- a/sphinx/builders/latex/nodes.py +++ b/sphinx/builders/latex/nodes.py @@ -4,7 +4,7 @@ Additional nodes for LaTeX writer. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/latex/theming.py b/sphinx/builders/latex/theming.py index da6a7fa04..5af79e8a2 100644 --- a/sphinx/builders/latex/theming.py +++ b/sphinx/builders/latex/theming.py @@ -4,7 +4,7 @@ Theming support for LaTeX builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -87,10 +87,12 @@ class UserTheme(Theme): try: value = self.config.get('theme', key) setattr(self, key, value) - except configparser.NoSectionError: - raise ThemeError(__('%r doesn\'t have "theme" setting') % filename) + except configparser.NoSectionError as exc: + raise ThemeError(__('%r doesn\'t have "theme" setting') % + filename) from exc except configparser.NoOptionError as exc: - raise ThemeError(__('%r doesn\'t have "%s" setting') % (filename, exc.args[0])) + raise ThemeError(__('%r doesn\'t have "%s" setting') % + (filename, exc.args[0])) from exc for key in self.OPTIONAL_CONFIG_KEYS: try: diff --git a/sphinx/builders/latex/transforms.py b/sphinx/builders/latex/transforms.py index 28841ad77..402cc3fe5 100644 --- a/sphinx/builders/latex/transforms.py +++ b/sphinx/builders/latex/transforms.py @@ -4,21 +4,20 @@ Transforms for LaTeX builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, List, Set, Tuple -from typing import cast +from typing import Any, Dict, List, Set, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node +from docutils.transforms.references import Substitutions from sphinx import addnodes from sphinx.application import Sphinx -from sphinx.builders.latex.nodes import ( - captioned_literal_block, footnotemark, footnotetext, math_reference, thebibliography -) +from sphinx.builders.latex.nodes import (captioned_literal_block, footnotemark, footnotetext, + math_reference, thebibliography) from sphinx.domains.citation import CitationDomain from sphinx.transforms import SphinxTransform from sphinx.transforms.post_transforms import SphinxPostTransform @@ -38,6 +37,18 @@ class FootnoteDocnameUpdater(SphinxTransform): node['docname'] = self.env.docname +class SubstitutionDefinitionsRemover(SphinxPostTransform): + """Remove ``substitution_definition node from doctrees.""" + + # should be invoked after Substitutions process + default_priority = Substitutions.default_priority + 1 + builders = ('latex',) + + def apply(self, **kwargs: Any) -> None: + for node in self.document.traverse(nodes.substitution_definition): + node.parent.remove(node) + + class ShowUrlsTransform(SphinxPostTransform): """Expand references to inline text or footnotes. @@ -602,6 +613,7 @@ class IndexInSectionTitleTransform(SphinxTransform): def setup(app: Sphinx) -> Dict[str, Any]: app.add_transform(FootnoteDocnameUpdater) + app.add_post_transform(SubstitutionDefinitionsRemover) app.add_post_transform(BibliographyTransform) app.add_post_transform(CitationReferenceTransform) app.add_post_transform(DocumentTargetTransform) diff --git a/sphinx/builders/latex/util.py b/sphinx/builders/latex/util.py index 0e3eb739d..4f2391c4e 100644 --- a/sphinx/builders/latex/util.py +++ b/sphinx/builders/latex/util.py @@ -4,7 +4,7 @@ Utilities for LaTeX builder. - :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 9fe689ec9..f813922ec 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -4,7 +4,7 @@ The CheckExternalLinksBuilder class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,28 +13,56 @@ import queue import re import socket import threading +import time +import warnings +from datetime import datetime, timezone +from email.utils import parsedate_to_datetime from html.parser import HTMLParser from os import path -from typing import Any, Dict, List, Set, Tuple -from urllib.parse import unquote +from typing import Any, Dict, List, NamedTuple, Optional, Set, Tuple, cast +from urllib.parse import unquote, urlparse from docutils import nodes -from docutils.nodes import Node -from requests.exceptions import HTTPError +from docutils.nodes import Element +from requests import Response +from requests.exceptions import HTTPError, TooManyRedirects from sphinx.application import Sphinx -from sphinx.builders import Builder +from sphinx.builders.dummy import DummyBuilder +from sphinx.deprecation import RemovedInSphinx50Warning from sphinx.locale import __ -from sphinx.util import encode_uri, requests, logging -from sphinx.util.console import ( # type: ignore - purple, red, darkgreen, darkgray, turquoise -) +from sphinx.transforms.post_transforms import SphinxPostTransform +from sphinx.util import encode_uri, logging, requests +from sphinx.util.console import darkgray, darkgreen, purple, red, turquoise # type: ignore from sphinx.util.nodes import get_node_line -from sphinx.util.requests import is_ssl_error - logger = logging.getLogger(__name__) +uri_re = re.compile('([a-z]+:)?//') # matches to foo:// and // (a protocol relative URL) + +Hyperlink = NamedTuple('Hyperlink', (('next_check', float), + ('uri', Optional[str]), + ('docname', Optional[str]), + ('lineno', Optional[int]))) +RateLimit = NamedTuple('RateLimit', (('delay', float), ('next_check', float))) + +DEFAULT_REQUEST_HEADERS = { + 'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8', +} +CHECK_IMMEDIATELY = 0 +QUEUE_POLL_SECS = 1 +DEFAULT_DELAY = 60.0 + + +def node_line_or_0(node: Element) -> int: + """ + PriorityQueue items must be comparable. The line number is part of the + tuple used by the PriorityQueue, keep an homogeneous type for comparison. + """ + warnings.warn('node_line_or_0() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + return get_node_line(node) or 0 + class AnchorCheckParser(HTMLParser): """Specialized HTML parser that looks for a specific anchor.""" @@ -70,7 +98,7 @@ def check_anchor(response: requests.requests.Response, anchor: str) -> bool: return parser.found -class CheckExternalLinksBuilder(Builder): +class CheckExternalLinksBuilder(DummyBuilder): """ Checks for broken external links. """ @@ -79,14 +107,15 @@ class CheckExternalLinksBuilder(Builder): '%(outdir)s/output.txt') def init(self) -> None: + self.hyperlinks = {} # type: Dict[str, Hyperlink] self.to_ignore = [re.compile(x) for x in self.app.config.linkcheck_ignore] self.anchors_ignore = [re.compile(x) for x in self.app.config.linkcheck_anchors_ignore] self.auth = [(re.compile(pattern), auth_info) for pattern, auth_info in self.app.config.linkcheck_auth] - self.good = set() # type: Set[str] - self.broken = {} # type: Dict[str, str] - self.redirected = {} # type: Dict[str, Tuple[str, int]] + self._good = set() # type: Set[str] + self._broken = {} # type: Dict[str, str] + self._redirected = {} # type: Dict[str, Tuple[str, int]] # set a timeout for non-responding servers socket.setdefaulttimeout(5.0) # create output file @@ -95,25 +124,62 @@ class CheckExternalLinksBuilder(Builder): open(path.join(self.outdir, 'output.json'), 'w').close() # create queues and worker threads - self.wqueue = queue.Queue() # type: queue.Queue + self.rate_limits = {} # type: Dict[str, RateLimit] + self.wqueue = queue.PriorityQueue() # type: queue.PriorityQueue self.rqueue = queue.Queue() # type: queue.Queue self.workers = [] # type: List[threading.Thread] for i in range(self.app.config.linkcheck_workers): - thread = threading.Thread(target=self.check_thread) - thread.setDaemon(True) + thread = threading.Thread(target=self.check_thread, daemon=True) thread.start() self.workers.append(thread) + @property + def good(self): + warnings.warn( + "%s.%s is deprecated." % (self.__class__.__name__, "good"), + RemovedInSphinx50Warning, + stacklevel=2, + ) + return self._good + + @property + def broken(self): + warnings.warn( + "%s.%s is deprecated." % (self.__class__.__name__, "broken"), + RemovedInSphinx50Warning, + stacklevel=2, + ) + return self._broken + + @property + def redirected(self): + warnings.warn( + "%s.%s is deprecated." % (self.__class__.__name__, "redirected"), + RemovedInSphinx50Warning, + stacklevel=2, + ) + return self._redirected + def check_thread(self) -> None: - kwargs = { - 'allow_redirects': True, - 'headers': { - 'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8', - }, - } + kwargs = {} if self.app.config.linkcheck_timeout: kwargs['timeout'] = self.app.config.linkcheck_timeout + def get_request_headers() -> Dict: + url = urlparse(uri) + candidates = ["%s://%s" % (url.scheme, url.netloc), + "%s://%s/" % (url.scheme, url.netloc), + uri, + "*"] + + for u in candidates: + if u in self.config.linkcheck_request_headers: + headers = dict(DEFAULT_REQUEST_HEADERS) + headers.update(self.config.linkcheck_request_headers[u]) + return headers + + return {} + def check_uri() -> Tuple[str, str, int]: # split off anchor if '#' in uri: @@ -139,11 +205,15 @@ class CheckExternalLinksBuilder(Builder): else: auth_info = None + # update request headers for the URL + kwargs['headers'] = get_request_headers() + try: if anchor and self.app.config.linkcheck_anchors: # Read the whole document and see if #anchor exists response = requests.get(req_url, stream=True, config=self.app.config, auth=auth_info, **kwargs) + response.raise_for_status() found = check_anchor(response, unquote(anchor)) if not found: @@ -152,29 +222,42 @@ class CheckExternalLinksBuilder(Builder): try: # try a HEAD request first, which should be easier on # the server and the network - response = requests.head(req_url, config=self.app.config, - auth=auth_info, **kwargs) + response = requests.head(req_url, allow_redirects=True, + config=self.app.config, auth=auth_info, + **kwargs) response.raise_for_status() - except HTTPError: + except (HTTPError, TooManyRedirects) as err: + if isinstance(err, HTTPError) and err.response.status_code == 429: + raise # retry with GET request if that fails, some servers # don't like HEAD requests. - response = requests.get(req_url, stream=True, config=self.app.config, + response = requests.get(req_url, stream=True, + config=self.app.config, auth=auth_info, **kwargs) response.raise_for_status() except HTTPError as err: if err.response.status_code == 401: # We'll take "Unauthorized" as working. return 'working', ' - unauthorized', 0 + elif err.response.status_code == 429: + next_check = self.limit_rate(err.response) + if next_check is not None: + self.wqueue.put((next_check, uri, docname, lineno), False) + return 'rate-limited', '', 0 + return 'broken', str(err), 0 elif err.response.status_code == 503: # We'll take "Service Unavailable" as ignored. return 'ignored', str(err), 0 else: return 'broken', str(err), 0 except Exception as err: - if is_ssl_error(err): - return 'ignored', str(err), 0 - else: - return 'broken', str(err), 0 + return 'broken', str(err), 0 + else: + netloc = urlparse(req_url).netloc + try: + del self.rate_limits[netloc] + except KeyError: + pass if response.url.rstrip('/') == req_url.rstrip('/'): return 'working', '', 0 else: @@ -188,18 +271,31 @@ class CheckExternalLinksBuilder(Builder): else: return 'redirected', new_url, 0 - def check() -> Tuple[str, str, int]: + def check(docname: str) -> Tuple[str, str, int]: # check for various conditions without bothering the network - if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'ftp:')): + if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'tel:')): return 'unchecked', '', 0 elif not uri.startswith(('http:', 'https:')): - return 'local', '', 0 - elif uri in self.good: + if uri_re.match(uri): + # non supported URI schemes (ex. ftp) + return 'unchecked', '', 0 + else: + srcdir = path.dirname(self.env.doc2path(docname)) + if path.exists(path.join(srcdir, uri)): + return 'working', '', 0 + else: + for rex in self.to_ignore: + if rex.match(uri): + return 'ignored', '', 0 + else: + self._broken[uri] = '' + return 'broken', '', 0 + elif uri in self._good: return 'working', 'old', 0 - elif uri in self.broken: - return 'broken', self.broken[uri], 0 - elif uri in self.redirected: - return 'redirected', self.redirected[uri][0], self.redirected[uri][1] + elif uri in self._broken: + return 'broken', self._broken[uri], 0 + elif uri in self._redirected: + return 'redirected', self._redirected[uri][0], self._redirected[uri][1] for rex in self.to_ignore: if rex.match(uri): return 'ignored', '', 0 @@ -211,20 +307,78 @@ class CheckExternalLinksBuilder(Builder): break if status == "working": - self.good.add(uri) + self._good.add(uri) elif status == "broken": - self.broken[uri] = info + self._broken[uri] = info elif status == "redirected": - self.redirected[uri] = (info, code) + self._redirected[uri] = (info, code) return (status, info, code) while True: - uri, docname, lineno = self.wqueue.get() + next_check, uri, docname, lineno = self.wqueue.get() if uri is None: break - status, info, code = check() - self.rqueue.put((uri, docname, lineno, status, info, code)) + netloc = urlparse(uri).netloc + try: + # Refresh rate limit. + # When there are many links in the queue, workers are all stuck waiting + # for responses, but the builder keeps queuing. Links in the queue may + # have been queued before rate limits were discovered. + next_check = self.rate_limits[netloc].next_check + except KeyError: + pass + if next_check > time.time(): + # Sleep before putting message back in the queue to avoid + # waking up other threads. + time.sleep(QUEUE_POLL_SECS) + self.wqueue.put((next_check, uri, docname, lineno), False) + self.wqueue.task_done() + continue + status, info, code = check(docname) + if status == 'rate-limited': + logger.info(darkgray('-rate limited- ') + uri + darkgray(' | sleeping...')) + else: + self.rqueue.put((uri, docname, lineno, status, info, code)) + self.wqueue.task_done() + + def limit_rate(self, response: Response) -> Optional[float]: + next_check = None + retry_after = response.headers.get("Retry-After") + if retry_after: + try: + # Integer: time to wait before next attempt. + delay = float(retry_after) + except ValueError: + try: + # An HTTP-date: time of next attempt. + until = parsedate_to_datetime(retry_after) + except (TypeError, ValueError): + # TypeError: Invalid date format. + # ValueError: Invalid date, e.g. Oct 52th. + pass + else: + next_check = datetime.timestamp(until) + delay = (until - datetime.now(timezone.utc)).total_seconds() + else: + next_check = time.time() + delay + netloc = urlparse(response.url).netloc + if next_check is None: + max_delay = self.app.config.linkcheck_rate_limit_timeout + try: + rate_limit = self.rate_limits[netloc] + except KeyError: + delay = DEFAULT_DELAY + else: + last_wait_time = rate_limit.delay + delay = 2.0 * last_wait_time + if delay > max_delay and last_wait_time < max_delay: + delay = max_delay + if delay > max_delay: + return None + next_check = time.time() + delay + self.rate_limits[netloc] = RateLimit(delay, next_check) + return next_check def process_result(self, result: Tuple[str, str, int, str, str, int]) -> None: uri, docname, lineno, status, info, code = result @@ -279,64 +433,73 @@ class CheckExternalLinksBuilder(Builder): lineno, uri + ' to ' + info) self.write_linkstat(linkstat) - def get_target_uri(self, docname: str, typ: str = None) -> str: - return '' - - def get_outdated_docs(self) -> Set[str]: - return self.env.found_docs + def write_entry(self, what: str, docname: str, filename: str, line: int, + uri: str) -> None: + with open(path.join(self.outdir, 'output.txt'), 'a') as output: + output.write("%s:%s: [%s] %s\n" % (filename, line, what, uri)) - def prepare_writing(self, docnames: Set[str]) -> None: - return + def write_linkstat(self, data: dict) -> None: + with open(path.join(self.outdir, 'output.json'), 'a') as output: + output.write(json.dumps(data)) + output.write('\n') - def write_doc(self, docname: str, doctree: Node) -> None: + def finish(self) -> None: logger.info('') n = 0 - # reference nodes - for refnode in doctree.traverse(nodes.reference): - if 'refuri' not in refnode: - continue - uri = refnode['refuri'] - lineno = get_node_line(refnode) - self.wqueue.put((uri, docname, lineno), False) + for hyperlink in self.hyperlinks.values(): + self.wqueue.put(hyperlink, False) n += 1 - # image nodes - for imgnode in doctree.traverse(nodes.image): - uri = imgnode['candidates'].get('?') - if uri and '://' in uri: - lineno = get_node_line(imgnode) - self.wqueue.put((uri, docname, lineno), False) - n += 1 - done = 0 while done < n: self.process_result(self.rqueue.get()) done += 1 - if self.broken: + if self._broken: self.app.statuscode = 1 - def write_entry(self, what: str, docname: str, filename: str, line: int, - uri: str) -> None: - with open(path.join(self.outdir, 'output.txt'), 'a') as output: - output.write("%s:%s: [%s] %s\n" % (filename, line, what, uri)) + self.wqueue.join() + # Shutdown threads. + for worker in self.workers: + self.wqueue.put((CHECK_IMMEDIATELY, None, None, None), False) - def write_linkstat(self, data: dict) -> None: - with open(path.join(self.outdir, 'output.json'), 'a') as output: - output.write(json.dumps(data)) - output.write('\n') - def finish(self) -> None: - for worker in self.workers: - self.wqueue.put((None, None, None), False) +class HyperlinkCollector(SphinxPostTransform): + builders = ('linkcheck',) + default_priority = 800 + + def run(self, **kwargs: Any) -> None: + builder = cast(CheckExternalLinksBuilder, self.app.builder) + hyperlinks = builder.hyperlinks + + # reference nodes + for refnode in self.document.traverse(nodes.reference): + if 'refuri' not in refnode: + continue + uri = refnode['refuri'] + lineno = get_node_line(refnode) + uri_info = Hyperlink(CHECK_IMMEDIATELY, uri, self.env.docname, lineno) + if uri not in hyperlinks: + hyperlinks[uri] = uri_info + + # image nodes + for imgnode in self.document.traverse(nodes.image): + uri = imgnode['candidates'].get('?') + if uri and '://' in uri: + lineno = get_node_line(imgnode) + uri_info = Hyperlink(CHECK_IMMEDIATELY, uri, self.env.docname, lineno) + if uri not in hyperlinks: + hyperlinks[uri] = uri_info def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(CheckExternalLinksBuilder) + app.add_post_transform(HyperlinkCollector) app.add_config_value('linkcheck_ignore', [], None) app.add_config_value('linkcheck_auth', [], None) + app.add_config_value('linkcheck_request_headers', {}, None) app.add_config_value('linkcheck_retries', 1, None) app.add_config_value('linkcheck_timeout', None, None, [int]) app.add_config_value('linkcheck_workers', 5, None) @@ -344,6 +507,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: # Anchors starting with ! are ignored since they are # commonly used for dynamic pages app.add_config_value('linkcheck_anchors_ignore', ["^!"], None) + app.add_config_value('linkcheck_rate_limit_timeout', 300.0, None) return { 'version': 'builtin', diff --git a/sphinx/builders/manpage.py b/sphinx/builders/manpage.py index 4166dece9..292f495de 100644 --- a/sphinx/builders/manpage.py +++ b/sphinx/builders/manpage.py @@ -4,7 +4,7 @@ Manual pages builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -20,13 +20,11 @@ from sphinx.builders import Builder from sphinx.config import Config from sphinx.errors import NoUri from sphinx.locale import __ -from sphinx.util import logging -from sphinx.util import progress_message +from sphinx.util import logging, progress_message from sphinx.util.console import darkgreen # type: ignore from sphinx.util.nodes import inline_all_toctrees -from sphinx.util.osutil import make_filename_from_project -from sphinx.writers.manpage import ManualPageWriter, ManualPageTranslator - +from sphinx.util.osutil import ensuredir, make_filename_from_project +from sphinx.writers.manpage import ManualPageTranslator, ManualPageWriter logger = logging.getLogger(__name__) @@ -80,7 +78,12 @@ class ManualPageBuilder(Builder): docsettings.authors = authors docsettings.section = section - targetname = '%s.%s' % (name, section) + if self.config.man_make_section_directory: + ensuredir(path.join(self.outdir, str(section))) + targetname = '%s/%s.%s' % (section, name, section) + else: + targetname = '%s.%s' % (name, section) + logger.info(darkgreen(targetname) + ' { ', nonl=True) destination = FileOutput( destination_path=path.join(self.outdir, targetname), @@ -115,6 +118,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('man_pages', default_man_pages, None) app.add_config_value('man_show_urls', False, None) + app.add_config_value('man_make_section_directory', False, None) return { 'version': 'builtin', diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index a4e73de9b..c5219dd75 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -4,7 +4,7 @@ Build input files for the Qt collection generator. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -17,13 +17,16 @@ import sphinx from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias - deprecated_alias('sphinx.builders.qthelp', { 'render_file': render_file, 'QtHelpBuilder': QtHelpBuilder, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'render_file': 'sphinxcontrib.qthelp.render_file', + 'QtHelpBuilder': 'sphinxcontrib.qthelp.QtHelpBuilder', + }) def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/builders/singlehtml.py b/sphinx/builders/singlehtml.py index b145109a6..2e72887e3 100644 --- a/sphinx/builders/singlehtml.py +++ b/sphinx/builders/singlehtml.py @@ -4,7 +4,7 @@ Single HTML builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -19,8 +19,7 @@ from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.environment.adapters.toctree import TocTree from sphinx.locale import __ -from sphinx.util import logging -from sphinx.util import progress_message +from sphinx.util import logging, progress_message from sphinx.util.console import darkgreen # type: ignore from sphinx.util.nodes import inline_all_toctrees @@ -193,7 +192,11 @@ deprecated_alias('sphinx.builders.html', { 'SingleFileHTMLBuilder': SingleFileHTMLBuilder, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'SingleFileHTMLBuilder': + 'sphinx.builders.singlehtml.SingleFileHTMLBuilder', + }) def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py index 5e2e6e240..1a56be0f9 100644 --- a/sphinx/builders/texinfo.py +++ b/sphinx/builders/texinfo.py @@ -4,7 +4,7 @@ Texinfo builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -16,23 +16,20 @@ from docutils import nodes from docutils.frontend import OptionParser from docutils.io import FileOutput -from sphinx import addnodes -from sphinx import package_dir +from sphinx import addnodes, package_dir from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.config import Config from sphinx.environment.adapters.asset import ImageAdapter from sphinx.errors import NoUri from sphinx.locale import _, __ -from sphinx.util import logging -from sphinx.util import progress_message, status_iterator +from sphinx.util import logging, progress_message, status_iterator from sphinx.util.console import darkgreen # type: ignore from sphinx.util.docutils import new_document from sphinx.util.fileutil import copy_asset_file from sphinx.util.nodes import inline_all_toctrees from sphinx.util.osutil import SEP, ensuredir, make_filename_from_project -from sphinx.writers.texinfo import TexinfoWriter, TexinfoTranslator - +from sphinx.writers.texinfo import TexinfoTranslator, TexinfoWriter logger = logging.getLogger(__name__) template_dir = os.path.join(package_dir, 'templates', 'texinfo') @@ -182,7 +179,8 @@ class TexinfoBuilder(Builder): try: imagedir = path.join(self.outdir, targetname + '-figures') ensuredir(imagedir) - copy_asset_file(path.join(self.srcdir, dest), imagedir) + copy_asset_file(path.join(self.srcdir, src), + path.join(imagedir, dest)) except Exception as err: logger.warning(__('cannot copy image file %r: %s'), path.join(self.srcdir, src), err) diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py index 89b041abd..ae770818c 100644 --- a/sphinx/builders/text.py +++ b/sphinx/builders/text.py @@ -4,7 +4,7 @@ Plain-text Sphinx builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -19,7 +19,7 @@ from sphinx.builders import Builder from sphinx.locale import __ from sphinx.util import logging from sphinx.util.osutil import ensuredir, os_path -from sphinx.writers.text import TextWriter, TextTranslator +from sphinx.writers.text import TextTranslator, TextWriter logger = logging.getLogger(__name__) diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py index 81d729def..1b051119b 100644 --- a/sphinx/builders/xml.py +++ b/sphinx/builders/xml.py @@ -4,7 +4,7 @@ Docutils-native XML and pseudo-XML builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -21,7 +21,7 @@ from sphinx.builders import Builder from sphinx.locale import __ from sphinx.util import logging from sphinx.util.osutil import ensuredir, os_path -from sphinx.writers.xml import XMLWriter, PseudoXMLWriter +from sphinx.writers.xml import PseudoXMLWriter, XMLWriter if False: # For type annotation diff --git a/sphinx/cmd/__init__.py b/sphinx/cmd/__init__.py index 33fbf747b..583e50ed7 100644 --- a/sphinx/cmd/__init__.py +++ b/sphinx/cmd/__init__.py @@ -4,6 +4,6 @@ Modules for command line executables. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/cmd/build.py b/sphinx/cmd/build.py index c4cf11cc4..32a89eb29 100644 --- a/sphinx/cmd/build.py +++ b/sphinx/cmd/build.py @@ -4,7 +4,7 @@ Build documentation from a provided source. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -16,7 +16,7 @@ import os import pdb import sys import traceback -from typing import Any, IO, List +from typing import IO, Any, List from docutils.utils import SystemMessage @@ -26,7 +26,7 @@ from sphinx.application import Sphinx from sphinx.errors import SphinxError from sphinx.locale import __ from sphinx.util import Tee, format_exception_cut_frames, save_traceback -from sphinx.util.console import red, nocolor, color_terminal, terminal_safe # type: ignore +from sphinx.util.console import color_terminal, nocolor, red, terminal_safe # type: ignore from sphinx.util.docutils import docutils_namespace, patch_docutils diff --git a/sphinx/cmd/make_mode.py b/sphinx/cmd/make_mode.py index aff2ea7f5..aaa40fba0 100644 --- a/sphinx/cmd/make_mode.py +++ b/sphinx/cmd/make_mode.py @@ -10,7 +10,7 @@ This is in its own module so that importing it is fast. It should not import the main Sphinx modules (like sphinx.applications, sphinx.builders). - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -22,10 +22,9 @@ from typing import List import sphinx from sphinx.cmd.build import build_main -from sphinx.util.console import color_terminal, nocolor, bold, blue # type: ignore +from sphinx.util.console import blue, bold, color_terminal, nocolor # type: ignore from sphinx.util.osutil import cd, rmtree - BUILDERS = [ ("", "html", "to make standalone HTML files"), ("", "dirhtml", "to make HTML files named index.html in directories"), diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index cad3c65e5..7d1c48f31 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -4,7 +4,7 @@ Quickly setup documentation source to work with Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -37,9 +37,8 @@ import sphinx.locale from sphinx import __display_version__, package_dir from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.locale import __ -from sphinx.util.console import ( # type: ignore - colorize, bold, red, turquoise, nocolor, color_terminal -) +from sphinx.util.console import (bold, color_terminal, colorize, nocolor, red, # type: ignore + turquoise) from sphinx.util.osutil import ensuredir from sphinx.util.template import SphinxRenderer @@ -489,8 +488,10 @@ def get_parser() -> argparse.ArgumentParser: help=__('project root')) group = parser.add_argument_group(__('Structure options')) - group.add_argument('--sep', action='store_true', default=None, + group.add_argument('--sep', action='store_true', dest='sep', default=None, help=__('if specified, separate source and build dirs')) + group.add_argument('--no-sep', action='store_false', dest='sep', + help=__('if specified, create build dir under source dir')) group.add_argument('--dot', metavar='DOT', default='_', help=__('replacement for dot in _templates etc.')) diff --git a/sphinx/config.py b/sphinx/config.py index 6e6c256c5..4c038b061 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -4,7 +4,7 @@ Build configuration file handling. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,10 +13,9 @@ import traceback import types import warnings from collections import OrderedDict -from os import path, getenv -from typing import ( - Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple, Union -) +from os import getenv, path +from typing import (Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple, + Union) from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.errors import ConfigError, ExtensionError @@ -99,7 +98,8 @@ class Config: # general options 'project': ('Python', 'env', []), 'author': ('unknown', 'env', []), - 'copyright': ('', 'html', []), + 'project_copyright': ('', 'html', [str]), + 'copyright': (lambda c: c.project_copyright, 'html', [str]), 'version': ('', 'env', []), 'release': ('', 'env', []), 'today': ('', 'env', []), @@ -131,7 +131,7 @@ class Config: 'rst_epilog': (None, 'env', [str]), 'rst_prolog': (None, 'env', [str]), 'trim_doctest_flags': (True, 'env', []), - 'primary_domain': ('py', 'env', [NoneType]), # type: ignore + 'primary_domain': ('py', 'env', [NoneType]), 'needs_sphinx': (None, None, [str]), 'needs_extensions': ({}, None, []), 'manpages_url': (None, 'env', []), @@ -181,6 +181,14 @@ class Config: defvalue = self.values[name][0] if self.values[name][2] == Any: return value + elif self.values[name][2] == {bool, str}: + if value == '0': + # given falsy string from command line option + return False + elif value == '1': + return True + else: + return value elif type(defvalue) is bool or self.values[name][2] == [bool]: if value == '0': # given falsy string from command line option @@ -196,9 +204,9 @@ class Config: elif isinstance(defvalue, int): try: return int(value) - except ValueError: + except ValueError as exc: raise ValueError(__('invalid number %r for config value %r, ignoring') % - (value, name)) + (value, name)) from exc elif hasattr(defvalue, '__call__'): return value elif defvalue is not None and not isinstance(defvalue, str): @@ -319,17 +327,17 @@ def eval_config_file(filename: str, tags: Tags) -> Dict[str, Any]: execfile_(filename, namespace) except SyntaxError as err: msg = __("There is a syntax error in your configuration file: %s\n") - raise ConfigError(msg % err) - except SystemExit: + raise ConfigError(msg % err) from err + except SystemExit as exc: msg = __("The configuration file (or one of the modules it imports) " "called sys.exit()") - raise ConfigError(msg) + raise ConfigError(msg) from exc except ConfigError: # pass through ConfigError from conf.py as is. It will be shown in console. raise - except Exception: + except Exception as exc: msg = __("There is a programmable error in your configuration file:\n\n%s") - raise ConfigError(msg % traceback.format_exc()) + raise ConfigError(msg % traceback.format_exc()) from exc return namespace @@ -359,6 +367,18 @@ def convert_source_suffix(app: "Sphinx", config: Config) -> None: "But `%r' is given." % source_suffix)) +def convert_highlight_options(app: "Sphinx", config: Config) -> None: + """Convert old styled highlight_options to new styled one. + + * old style: options + * new style: dict that maps language names to options + """ + options = config.highlight_options + if options and not all(isinstance(v, dict) for v in options.values()): + # old styled option detected because all values are not dictionary. + config.highlight_options = {config.highlight_language: options} # type: ignore + + def init_numfig_format(app: "Sphinx", config: Config) -> None: """Initialize :confval:`numfig_format`.""" numfig_format = {'section': _('Section %s'), @@ -479,6 +499,7 @@ def check_master_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str], def setup(app: "Sphinx") -> Dict[str, Any]: app.connect('config-inited', convert_source_suffix, priority=800) + app.connect('config-inited', convert_highlight_options, priority=800) app.connect('config-inited', init_numfig_format, priority=800) app.connect('config-inited', correct_copyright_year, priority=800) app.connect('config-inited', check_confval_types, priority=800) diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py index 6f0fb2db4..161d7bcac 100644 --- a/sphinx/deprecation.py +++ b/sphinx/deprecation.py @@ -4,7 +4,7 @@ Sphinx deprecation classes and utilities. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -26,30 +26,46 @@ class RemovedInSphinx50Warning(PendingDeprecationWarning): pass +class RemovedInSphinx60Warning(PendingDeprecationWarning): + pass + + RemovedInNextVersionWarning = RemovedInSphinx40Warning -def deprecated_alias(modname: str, objects: Dict, warning: "Type[Warning]") -> None: +def deprecated_alias(modname: str, objects: Dict[str, object], + warning: "Type[Warning]", names: Dict[str, str] = None) -> None: module = import_module(modname) - sys.modules[modname] = _ModuleWrapper(module, modname, objects, warning) # type: ignore + sys.modules[modname] = _ModuleWrapper( # type: ignore + module, modname, objects, warning, names) class _ModuleWrapper: - def __init__(self, module: Any, modname: str, objects: Dict, warning: "Type[Warning]" - ) -> None: + def __init__(self, module: Any, modname: str, + objects: Dict[str, object], + warning: "Type[Warning]", + names: Dict[str, str]) -> None: self._module = module self._modname = modname self._objects = objects self._warning = warning + self._names = names def __getattr__(self, name: str) -> Any: - if name in self._objects: - warnings.warn("%s.%s is deprecated. Check CHANGES for Sphinx " - "API modifications." % (self._modname, name), + if name not in self._objects: + return getattr(self._module, name) + + canonical_name = self._names.get(name, None) + if canonical_name is not None: + warnings.warn( + "The alias '{}.{}' is deprecated, use '{}' instead. Check CHANGES for " + "Sphinx API modifications.".format(self._modname, name, canonical_name), + self._warning, stacklevel=3) + else: + warnings.warn("{}.{} is deprecated. Check CHANGES for Sphinx " + "API modifications.".format(self._modname, name), self._warning, stacklevel=3) - return self._objects[name] - - return getattr(self._module, name) + return self._objects[name] class DeprecatedDict(dict): diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index 574962d81..e386b3eaa 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -4,13 +4,12 @@ Handlers for additional ReST directives. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re -from typing import Any, Dict, List, Tuple -from typing import cast +from typing import Any, Dict, Generic, List, Tuple, TypeVar, cast from docutils import nodes from docutils.nodes import Node @@ -18,9 +17,8 @@ from docutils.parsers.rst import directives, roles from sphinx import addnodes from sphinx.addnodes import desc_signature -from sphinx.deprecation import ( - RemovedInSphinx40Warning, RemovedInSphinx50Warning, deprecated_alias -) +from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning, + deprecated_alias) from sphinx.util import docutils from sphinx.util.docfields import DocFieldTransformer, Field, TypedField from sphinx.util.docutils import SphinxDirective @@ -35,6 +33,8 @@ if False: nl_escape_re = re.compile(r'\\\n') strip_backslash_re = re.compile(r'\\(.)') +T = TypeVar('T') + def optional_int(argument: str) -> int: """ @@ -49,7 +49,7 @@ def optional_int(argument: str) -> int: return value -class ObjectDescription(SphinxDirective): +class ObjectDescription(SphinxDirective, Generic[T]): """ Directive to describe a class, function or similar object. Not used directly, but subclassed (in domain-specific directives) to add custom @@ -99,7 +99,7 @@ class ObjectDescription(SphinxDirective): else: return [line.strip() for line in lines] - def handle_signature(self, sig: str, signode: desc_signature) -> Any: + def handle_signature(self, sig: str, signode: desc_signature) -> T: """ Parse the signature *sig* into individual nodes and append them to *signode*. If ValueError is raised, parsing is aborted and the whole @@ -111,7 +111,7 @@ class ObjectDescription(SphinxDirective): """ raise ValueError - def add_target_and_index(self, name: Any, sig: str, signode: desc_signature) -> None: + def add_target_and_index(self, name: T, sig: str, signode: desc_signature) -> None: """ Add cross-reference IDs and entries to self.indexnode, if applicable. @@ -175,7 +175,7 @@ class ObjectDescription(SphinxDirective): if self.domain: node['classes'].append(self.domain) - self.names = [] # type: List[Any] + self.names = [] # type: List[T] signatures = self.get_signatures() for i, sig in enumerate(signatures): # add a signature node for each signature in the current unit @@ -266,16 +266,10 @@ class DefaultDomain(SphinxDirective): self.env.temp_data['default_domain'] = self.env.domains.get(domain_name) return [] -from sphinx.directives.code import ( # noqa - Highlight, CodeBlock, LiteralInclude -) -from sphinx.directives.other import ( # noqa - TocTree, Author, VersionChange, SeeAlso, - TabularColumns, Centered, Acks, HList, Only, Include, Class -) -from sphinx.directives.patches import ( # noqa - Figure, Meta -) +from sphinx.directives.code import CodeBlock, Highlight, LiteralInclude # noqa +from sphinx.directives.other import (Acks, Author, Centered, Class, HList, Include, # noqa + Only, SeeAlso, TabularColumns, TocTree, VersionChange) +from sphinx.directives.patches import Figure, Meta # noqa from sphinx.domains.index import IndexDirective # noqa deprecated_alias('sphinx.directives', @@ -298,13 +292,35 @@ deprecated_alias('sphinx.directives', 'Figure': Figure, 'Meta': Meta, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'Highlight': 'sphinx.directives.code.Highlight', + 'CodeBlock': 'sphinx.directives.code.CodeBlock', + 'LiteralInclude': 'sphinx.directives.code.LiteralInclude', + 'TocTree': 'sphinx.directives.other.TocTree', + 'Author': 'sphinx.directives.other.Author', + 'Index': 'sphinx.directives.other.IndexDirective', + 'VersionChange': 'sphinx.directives.other.VersionChange', + 'SeeAlso': 'sphinx.directives.other.SeeAlso', + 'TabularColumns': 'sphinx.directives.other.TabularColumns', + 'Centered': 'sphinx.directives.other.Centered', + 'Acks': 'sphinx.directives.other.Acks', + 'HList': 'sphinx.directives.other.HList', + 'Only': 'sphinx.directives.other.Only', + 'Include': 'sphinx.directives.other.Include', + 'Class': 'sphinx.directives.other.Class', + 'Figure': 'sphinx.directives.patches.Figure', + 'Meta': 'sphinx.directives.patches.Meta', + }) deprecated_alias('sphinx.directives', { 'DescDirective': ObjectDescription, }, - RemovedInSphinx50Warning) + RemovedInSphinx50Warning, + { + 'DescDirective': 'sphinx.directives.ObjectDescription', + }) def setup(app: "Sphinx") -> Dict[str, Any]: diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index 8c19dd0c5..e01b8f9ec 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -2,11 +2,12 @@ sphinx.directives.code ~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import sys +import textwrap import warnings from difflib import unified_diff from typing import Any, Dict, List, Tuple @@ -19,9 +20,9 @@ from docutils.statemachine import StringList from sphinx import addnodes from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.directives import optional_int from sphinx.locale import __ -from sphinx.util import logging -from sphinx.util import parselinenos +from sphinx.util import logging, parselinenos from sphinx.util.docutils import SphinxDirective if False: @@ -69,10 +70,10 @@ class HighlightLang(Highlight): def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]: if not dedent: - return lines + return textwrap.dedent(''.join(lines)).splitlines(True) if any(s[:dedent].strip() for s in lines): - logger.warning(__('Over dedent has detected'), location=location) + logger.warning(__('non-whitespace stripped by dedent'), location=location) new_lines = [] for line in lines: @@ -118,7 +119,7 @@ class CodeBlock(SphinxDirective): option_spec = { 'force': directives.flag, 'linenos': directives.flag, - 'dedent': int, + 'dedent': optional_int, 'lineno-start': int, 'emphasize-lines': directives.unchanged_required, 'caption': directives.unchanged_required, @@ -227,12 +228,13 @@ class LiteralIncludeReader: text = text.expandtabs(self.options['tab-width']) return text.splitlines(True) - except OSError: - raise OSError(__('Include file %r not found or reading it failed') % filename) - except UnicodeError: + except OSError as exc: + raise OSError(__('Include file %r not found or reading it failed') % + filename) from exc + except UnicodeError as exc: raise UnicodeError(__('Encoding %r used for reading included file %r seems to ' 'be wrong, try giving an :encoding: option') % - (self.encoding, filename)) + (self.encoding, filename)) from exc def read(self, location: Tuple[str, int] = None) -> Tuple[str, int]: if 'diff' in self.options: @@ -391,7 +393,7 @@ class LiteralInclude(SphinxDirective): optional_arguments = 0 final_argument_whitespace = True option_spec = { - 'dedent': int, + 'dedent': optional_int, 'linenos': directives.flag, 'lineno-start': int, 'lineno-match': directives.flag, diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index e4fcc0f5c..9325cbe4f 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -2,13 +2,12 @@ sphinx.directives.other ~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re -from typing import Any, Dict, List -from typing import cast +from typing import Any, Dict, List, cast from docutils import nodes from docutils.nodes import Element, Node @@ -21,7 +20,7 @@ from sphinx import addnodes from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.domains.changeset import VersionChange # NOQA # for compatibility from sphinx.locale import _ -from sphinx.util import url_re, docname_join +from sphinx.util import docname_join, url_re from sphinx.util.docutils import SphinxDirective from sphinx.util.matching import Matcher, patfilter from sphinx.util.nodes import explicit_title_re @@ -368,7 +367,10 @@ deprecated_alias('sphinx.directives.other', { 'Index': IndexDirective, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'Index': 'sphinx.domains.index.IndexDirective', + }) def setup(app: "Sphinx") -> Dict[str, Any]: diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py index 4b73a7955..1eae6d0c8 100644 --- a/sphinx/directives/patches.py +++ b/sphinx/directives/patches.py @@ -2,17 +2,16 @@ sphinx.directives.patches ~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, List, Tuple -from typing import cast +from typing import Any, Dict, List, Tuple, cast from docutils import nodes from docutils.nodes import Node, make_id, system_message from docutils.parsers.rst import directives -from docutils.parsers.rst.directives import images, html, tables +from docutils.parsers.rst.directives import html, images, tables from sphinx import addnodes from sphinx.directives import optional_int diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 11b3a4604..60142f584 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -5,13 +5,12 @@ Support for domains, which are groupings of description directives and roles describing e.g. constructs of one programming language. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import copy -from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Union -from typing import cast +from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Union, cast from docutils import nodes from docutils.nodes import Element, Node, system_message @@ -26,6 +25,7 @@ from sphinx.util.typing import RoleFunction if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.builders import Builder from sphinx.environment import BuildEnvironment diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 36a8f1f65..5336b003c 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -4,42 +4,49 @@ The C language domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re -from typing import ( - Any, Callable, Dict, Generator, Iterator, List, Type, Tuple, Union -) -from typing import cast +from typing import (Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, + Union, cast) from docutils import nodes from docutils.nodes import Element, Node, TextElement, system_message +from docutils.parsers.rst import directives from sphinx import addnodes from sphinx.addnodes import pending_xref from sphinx.application import Sphinx from sphinx.builders import Builder +from sphinx.deprecation import RemovedInSphinx50Warning from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ from sphinx.roles import SphinxRole, XRefRole +from sphinx.transforms import SphinxTransform +from sphinx.transforms.post_transforms import ReferencesResolver from sphinx.util import logging -from sphinx.util.cfamily import ( - NoOldIdError, ASTBaseBase, verify_description_mode, StringifyTransform, - BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral, - identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re, - hex_literal_re, binary_literal_re, integers_literal_suffix_re, - float_literal_re, float_literal_suffix_re, - char_literal_re -) +from sphinx.util.cfamily import (ASTAttribute, ASTBaseBase, ASTBaseParenExprList, BaseParser, + DefinitionError, NoOldIdError, StringifyTransform, + UnsupportedMultiCharacterCharLiteral, anon_identifier_re, + binary_literal_re, char_literal_re, float_literal_re, + float_literal_suffix_re, hex_literal_re, identifier_re, + integer_literal_re, integers_literal_suffix_re, + octal_literal_re, verify_description_mode) from sphinx.util.docfields import Field, TypedField from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import make_refnode logger = logging.getLogger(__name__) +T = TypeVar('T') + +DeclarationType = Union[ + "ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator", + "ASTType", "ASTTypeWithInit", "ASTMacro", +] # https://en.cppreference.com/w/c/keyword _keywords = [ @@ -106,6 +113,9 @@ class ASTIdentifier(ASTBaseBase): assert len(identifier) != 0 self.identifier = identifier + def __eq__(self, other: Any) -> bool: + return type(other) is ASTIdentifier and self.identifier == other.identifier + def is_anon(self) -> bool: return self.identifier[0] == '@' @@ -127,8 +137,7 @@ class ASTIdentifier(ASTBaseBase): reftype='identifier', reftarget=targetText, modname=None, classname=None) - # key = symbol.get_lookup_key() - # pnode['c:parent_key'] = key + pnode['c:parent_key'] = symbol.get_lookup_key() if self.is_anon(): pnode += nodes.strong(text="[anonymous]") else: @@ -627,6 +636,10 @@ class ASTFunctionParameter(ASTBase): self.arg = arg self.ellipsis = ellipsis + def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: + # the anchor will be our parent + return symbol.parent.declaration.get_id(version, prefixed=False) + def _stringify(self, transform: StringifyTransform) -> str: if self.ellipsis: return '...' @@ -643,8 +656,9 @@ class ASTFunctionParameter(ASTBase): class ASTParameters(ASTBase): - def __init__(self, args: List[ASTFunctionParameter]) -> None: + def __init__(self, args: List[ASTFunctionParameter], attrs: List[ASTAttribute]) -> None: self.args = args + self.attrs = attrs @property def function_params(self) -> List[ASTFunctionParameter]: @@ -660,6 +674,9 @@ class ASTParameters(ASTBase): first = False res.append(str(a)) res.append(')') + for attr in self.attrs: + res.append(' ') + res.append(transform(attr)) return ''.join(res) def describe_signature(self, signode: TextElement, mode: str, @@ -674,6 +691,9 @@ class ASTParameters(ASTBase): arg.describe_signature(param, 'markType', env, symbol=symbol) paramlist += param signode += paramlist + for attr in self.attrs: + signode += nodes.Text(' ') + attr.describe_signature(signode) class ASTDeclSpecsSimple(ASTBaseBase): @@ -1053,7 +1073,7 @@ class ASTDeclaratorParen(ASTDeclarator): # Initializer ################################################################################ -class ASTParenExprList(ASTBase): +class ASTParenExprList(ASTBaseParenExprList): def __init__(self, exprs: List[ASTExpression]) -> None: self.exprs = exprs @@ -1133,6 +1153,9 @@ class ASTType(ASTBase): def name(self) -> ASTNestedName: return self.decl.name + def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: + return symbol.get_full_nested_name().get_id(version) + @property def function_params(self) -> List[ASTFunctionParameter]: return self.decl.function_params @@ -1175,6 +1198,9 @@ class ASTTypeWithInit(ASTBase): def name(self) -> ASTNestedName: return self.type.name + def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: + return self.type.get_id(version, objectType, symbol) + def _stringify(self, transform: StringifyTransform) -> str: res = [] res.append(transform(self.type)) @@ -1191,13 +1217,17 @@ class ASTTypeWithInit(ASTBase): class ASTMacroParameter(ASTBase): - def __init__(self, arg: ASTNestedName, ellipsis: bool = False) -> None: + def __init__(self, arg: ASTNestedName, ellipsis: bool = False, + variadic: bool = False) -> None: self.arg = arg self.ellipsis = ellipsis + self.variadic = variadic def _stringify(self, transform: StringifyTransform) -> str: if self.ellipsis: return '...' + elif self.variadic: + return transform(self.arg) + '...' else: return transform(self.arg) @@ -1206,6 +1236,9 @@ class ASTMacroParameter(ASTBase): verify_description_mode(mode) if self.ellipsis: signode += nodes.Text('...') + elif self.variadic: + name = str(self) + signode += nodes.emphasis(name, name) else: self.arg.describe_signature(signode, mode, env, symbol=symbol) @@ -1219,6 +1252,9 @@ class ASTMacro(ASTBase): def name(self) -> ASTNestedName: return self.ident + def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: + return symbol.get_full_nested_name().get_id(version) + def _stringify(self, transform: StringifyTransform) -> str: res = [] res.append(transform(self.ident)) @@ -1319,7 +1355,8 @@ class ASTEnumerator(ASTBase): class ASTDeclaration(ASTBaseBase): - def __init__(self, objectType: str, directiveType: str, declaration: Any, + def __init__(self, objectType: str, directiveType: str, + declaration: Union[DeclarationType, ASTFunctionParameter], semicolon: bool = False) -> None: self.objectType = objectType self.directiveType = directiveType @@ -1330,20 +1367,26 @@ class ASTDeclaration(ASTBaseBase): # set by CObject._add_enumerator_to_parent self.enumeratorScopedSymbol = None # type: Symbol + def clone(self) -> "ASTDeclaration": + return ASTDeclaration(self.objectType, self.directiveType, + self.declaration.clone(), self.semicolon) + @property def name(self) -> ASTNestedName: - return self.declaration.name + decl = cast(DeclarationType, self.declaration) + return decl.name @property def function_params(self) -> List[ASTFunctionParameter]: if self.objectType != 'function': return None - return self.declaration.function_params + decl = cast(ASTType, self.declaration) + return decl.function_params def get_id(self, version: int, prefixed: bool = True) -> str: if self.objectType == 'enumerator' and self.enumeratorScopedSymbol: return self.enumeratorScopedSymbol.declaration.get_id(version, prefixed) - id_ = self.symbol.get_full_nested_name().get_id(version) + id_ = self.declaration.get_id(version, self.objectType, self.symbol) if prefixed: return _id_prefix[version] + id_ else: @@ -1386,7 +1429,8 @@ class ASTDeclaration(ASTBaseBase): elif self.objectType == 'enumerator': mainDeclNode += addnodes.desc_annotation('enumerator ', 'enumerator ') elif self.objectType == 'type': - prefix = self.declaration.get_type_declaration_prefix() + decl = cast(ASTType, self.declaration) + prefix = decl.get_type_declaration_prefix() prefix += ' ' mainDeclNode += addnodes.desc_annotation(prefix, prefix) else: @@ -1419,6 +1463,16 @@ class Symbol: debug_lookup = False debug_show_tree = False + def __copy__(self): + assert False # shouldn't happen + + def __deepcopy__(self, memo): + if self.parent: + assert False # shouldn't happen + else: + # the domain base class makes a copy of the initial data, which is fine + return Symbol(None, None, None, None, None) + @staticmethod def debug_print(*args: Any) -> None: print(Symbol.debug_indent_string * Symbol.debug_indent, end="") @@ -1440,7 +1494,7 @@ class Symbol: return super().__setattr__(key, value) def __init__(self, parent: "Symbol", ident: ASTIdentifier, - declaration: ASTDeclaration, docname: str) -> None: + declaration: ASTDeclaration, docname: str, line: int) -> None: self.parent = parent # declarations in a single directive are linked together self.siblingAbove = None # type: Symbol @@ -1448,6 +1502,7 @@ class Symbol: self.ident = ident self.declaration = declaration self.docname = docname + self.line = line self.isRedeclaration = False self._assert_invariants() @@ -1463,15 +1518,18 @@ class Symbol: # Do symbol addition after self._children has been initialised. self._add_function_params() - def _fill_empty(self, declaration: ASTDeclaration, docname: str) -> None: + def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> None: self._assert_invariants() - assert not self.declaration - assert not self.docname - assert declaration - assert docname + assert self.declaration is None + assert self.docname is None + assert self.line is None + assert declaration is not None + assert docname is not None + assert line is not None self.declaration = declaration self.declaration.symbol = self self.docname = docname + self.line = line self._assert_invariants() # and symbol addition should be done as well self._add_function_params() @@ -1495,7 +1553,7 @@ class Symbol: decl = ASTDeclaration('functionParam', None, p) assert not nn.rooted assert len(nn.names) == 1 - self._add_symbols(nn, decl, self.docname) + self._add_symbols(nn, decl, self.docname, self.line) if Symbol.debug_lookup: Symbol.debug_indent -= 1 @@ -1507,26 +1565,27 @@ class Symbol: self.parent = None def clear_doc(self, docname: str) -> None: - newChildren = [] # type: List[Symbol] for sChild in self._children: sChild.clear_doc(docname) if sChild.declaration and sChild.docname == docname: sChild.declaration = None sChild.docname = None + sChild.line = None if sChild.siblingAbove is not None: sChild.siblingAbove.siblingBelow = sChild.siblingBelow if sChild.siblingBelow is not None: sChild.siblingBelow.siblingAbove = sChild.siblingAbove sChild.siblingAbove = None sChild.siblingBelow = None - newChildren.append(sChild) - self._children = newChildren def get_all_symbols(self) -> Iterator["Symbol"]: yield self for sChild in self._children: - for s in sChild.get_all_symbols(): - yield s + yield from sChild.get_all_symbols() + + @property + def children(self) -> Iterator["Symbol"]: + yield from self._children @property def children_recurse_anon(self) -> Iterator["Symbol"]: @@ -1703,7 +1762,7 @@ class Symbol: return SymbolLookupResult(symbols, parentSymbol, ident) def _add_symbols(self, nestedName: ASTNestedName, - declaration: ASTDeclaration, docname: str) -> "Symbol": + declaration: ASTDeclaration, docname: str, line: int) -> "Symbol": # TODO: further simplification from C++ to C # Used for adding a whole path of symbols, where the last may or may not # be an actual declaration. @@ -1712,9 +1771,9 @@ class Symbol: Symbol.debug_indent += 1 Symbol.debug_print("_add_symbols:") Symbol.debug_indent += 1 - Symbol.debug_print("nn: ", nestedName) - Symbol.debug_print("decl: ", declaration) - Symbol.debug_print("doc: ", docname) + Symbol.debug_print("nn: ", nestedName) + Symbol.debug_print("decl: ", declaration) + Symbol.debug_print("location: {}:{}".format(docname, line)) def onMissingQualifiedSymbol(parentSymbol: "Symbol", ident: ASTIdentifier) -> "Symbol": if Symbol.debug_lookup: @@ -1724,7 +1783,7 @@ class Symbol: Symbol.debug_print("ident: ", ident) Symbol.debug_indent -= 2 return Symbol(parent=parentSymbol, ident=ident, - declaration=None, docname=None) + declaration=None, docname=None, line=None) lookupResult = self._symbol_lookup(nestedName, onMissingQualifiedSymbol, @@ -1740,12 +1799,12 @@ class Symbol: Symbol.debug_indent += 1 Symbol.debug_print("ident: ", lookupResult.ident) Symbol.debug_print("declaration: ", declaration) - Symbol.debug_print("docname: ", docname) + Symbol.debug_print("location: {}:{}".format(docname, line)) Symbol.debug_indent -= 1 symbol = Symbol(parent=lookupResult.parentSymbol, ident=lookupResult.ident, declaration=declaration, - docname=docname) + docname=docname, line=line) if Symbol.debug_lookup: Symbol.debug_indent -= 2 return symbol @@ -1758,7 +1817,7 @@ class Symbol: if not declaration: if Symbol.debug_lookup: - Symbol.debug_print("no delcaration") + Symbol.debug_print("no declaration") Symbol.debug_indent -= 2 # good, just a scope creation # TODO: what if we have more than one symbol? @@ -1793,7 +1852,7 @@ class Symbol: symbol = Symbol(parent=lookupResult.parentSymbol, ident=lookupResult.ident, declaration=declaration, - docname=docname) + docname=docname, line=line) if Symbol.debug_lookup: Symbol.debug_print("end: creating candidate symbol") return symbol @@ -1859,7 +1918,7 @@ class Symbol: # .. namespace:: Test # .. namespace:: nullptr # .. class:: Test - symbol._fill_empty(declaration, docname) + symbol._fill_empty(declaration, docname, line) return symbol def merge_with(self, other: "Symbol", docnames: List[str], @@ -1880,13 +1939,15 @@ class Symbol: continue if otherChild.declaration and otherChild.docname in docnames: if not ourChild.declaration: - ourChild._fill_empty(otherChild.declaration, otherChild.docname) + ourChild._fill_empty(otherChild.declaration, + otherChild.docname, otherChild.line) elif ourChild.docname != otherChild.docname: name = str(ourChild.declaration) - msg = __("Duplicate declaration, also defined in '%s'.\n" - "Declaration is '%s'.") - msg = msg % (ourChild.docname, name) - logger.warning(msg, location=otherChild.docname) + msg = __("Duplicate C declaration, also defined at %s:%s.\n" + "Declaration is '.. c:%s:: %s'.") + msg = msg % (ourChild.docname, ourChild.line, + ourChild.declaration.directiveType, name) + logger.warning(msg, location=(otherChild.docname, otherChild.line)) else: # Both have declarations, and in the same docname. # This can apparently happen, it should be safe to @@ -1900,19 +1961,21 @@ class Symbol: if Symbol.debug_lookup: Symbol.debug_indent += 1 Symbol.debug_print("add_name:") - res = self._add_symbols(nestedName, declaration=None, docname=None) + res = self._add_symbols(nestedName, declaration=None, docname=None, line=None) if Symbol.debug_lookup: Symbol.debug_indent -= 1 return res - def add_declaration(self, declaration: ASTDeclaration, docname: str) -> "Symbol": + def add_declaration(self, declaration: ASTDeclaration, + docname: str, line: int) -> "Symbol": if Symbol.debug_lookup: Symbol.debug_indent += 1 Symbol.debug_print("add_declaration:") - assert declaration - assert docname + assert declaration is not None + assert docname is not None + assert line is not None nestedName = declaration.name - res = self._add_symbols(nestedName, declaration, docname) + res = self._add_symbols(nestedName, declaration, docname, line) if Symbol.debug_lookup: Symbol.debug_indent -= 1 return res @@ -2300,7 +2363,8 @@ class DefinitionParser(BaseParser): errs = [] errs.append((exCast, "If type cast expression")) errs.append((exUnary, "If unary expression")) - raise self._make_multi_error(errs, "Error in cast expression.") + raise self._make_multi_error(errs, + "Error in cast expression.") from exUnary else: return self._parse_unary_expression() @@ -2544,7 +2608,15 @@ class DefinitionParser(BaseParser): self.fail( 'Expecting "," or ")" in parameters, ' 'got "%s".' % self.current_char) - return ASTParameters(args) + + attrs = [] + while True: + attr = self._parse_attribute() + if attr is None: + break + attrs.append(attr) + + return ASTParameters(args, attrs) def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple: """Just parse the simple ones.""" @@ -2767,7 +2839,7 @@ class DefinitionParser(BaseParser): msg += " (e.g., 'void (*f(int arg))(double)')" prevErrors.append((exNoPtrParen, msg)) header = "Error in declarator" - raise self._make_multi_error(prevErrors, header) + raise self._make_multi_error(prevErrors, header) from exNoPtrParen pos = self.pos try: return self._parse_declarator_name_suffix(named, paramMode, typed) @@ -2775,7 +2847,7 @@ class DefinitionParser(BaseParser): self.pos = pos prevErrors.append((e, "If declarator-id")) header = "Error in declarator or parameters" - raise self._make_multi_error(prevErrors, header) + raise self._make_multi_error(prevErrors, header) from e def _parse_initializer(self, outer: str = None, allowFallback: bool = True ) -> ASTInitializer: @@ -2843,7 +2915,7 @@ class DefinitionParser(BaseParser): if True: header = "Type must be either just a name or a " header += "typedef-like declaration." - raise self._make_multi_error(prevErrors, header) + raise self._make_multi_error(prevErrors, header) from exTyped else: # For testing purposes. # do it again to get the proper traceback (how do you @@ -2894,9 +2966,16 @@ class DefinitionParser(BaseParser): if not self.match(identifier_re): self.fail("Expected identifier in macro parameters.") nn = ASTNestedName([ASTIdentifier(self.matched_text)], rooted=False) - arg = ASTMacroParameter(nn) - args.append(arg) + # Allow named variadic args: + # https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html self.skip_ws() + if self.skip_string_and_ws('...'): + args.append(ASTMacroParameter(nn, False, True)) + self.skip_ws() + if not self.skip_string(')'): + self.fail('Expected ")" after "..." in macro parameters.') + break + args.append(ASTMacroParameter(nn)) if self.skip_string_and_ws(','): continue elif self.skip_string_and_ws(')'): @@ -2931,6 +3010,23 @@ class DefinitionParser(BaseParser): init = ASTInitializer(initVal) return ASTEnumerator(name, init) + def parse_pre_v3_type_definition(self) -> ASTDeclaration: + self.skip_ws() + declaration = None # type: DeclarationType + if self.skip_word('struct'): + typ = 'struct' + declaration = self._parse_struct() + elif self.skip_word('union'): + typ = 'union' + declaration = self._parse_union() + elif self.skip_word('enum'): + typ = 'enum' + declaration = self._parse_enum() + else: + self.fail("Could not parse pre-v3 type directive." + " Must start with 'struct', 'union', or 'enum'.") + return ASTDeclaration(typ, typ, declaration, False) + def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclaration: if objectType not in ('function', 'member', 'macro', 'struct', 'union', 'enum', 'enumerator', 'type'): @@ -2939,7 +3035,7 @@ class DefinitionParser(BaseParser): 'macro', 'struct', 'union', 'enum', 'enumerator', 'type'): raise Exception('Internal error, unknown directiveType "%s".' % directiveType) - declaration = None # type: Any + declaration = None # type: DeclarationType if objectType == 'member': declaration = self._parse_type_with_init(named=True, outer='member') elif objectType == 'function': @@ -2994,7 +3090,7 @@ class DefinitionParser(BaseParser): errs = [] errs.append((exExpr, "If expression")) errs.append((exType, "If type")) - raise self._make_multi_error(errs, header) + raise self._make_multi_error(errs, header) from exType return res @@ -3002,7 +3098,7 @@ def _make_phony_error_name() -> ASTNestedName: return ASTNestedName([ASTIdentifier("PhonyNameDueToError")], rooted=False) -class CObject(ObjectDescription): +class CObject(ObjectDescription[ASTDeclaration]): """ Description of a C language object. """ @@ -3017,6 +3113,10 @@ class CObject(ObjectDescription): names=('rtype',)), ] + option_spec = { + 'noindexentry': directives.flag, + } + def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None: assert ast.objectType == 'enumerator' # find the parent, if it exists && is an enum @@ -3052,7 +3152,7 @@ class CObject(ObjectDescription): declClone.enumeratorScopedSymbol = symbol Symbol(parent=targetSymbol, ident=symbol.ident, declaration=declClone, - docname=self.env.docname) + docname=self.env.docname, line=self.get_source_info()[1]) def add_target_and_index(self, ast: ASTDeclaration, sig: str, signode: TextElement) -> None: @@ -3082,11 +3182,9 @@ class CObject(ObjectDescription): self.state.document.note_explicit_target(signode) - domain = cast(CDomain, self.env.get_domain('c')) - domain.note_object(name, self.objtype, newestId) - - indexText = self.get_index_text(name) - self.indexnode['entries'].append(('single', indexText, newestId, '', None)) + if 'noindexentry' not in self.options: + indexText = self.get_index_text(name) + self.indexnode['entries'].append(('single', indexText, newestId, '', None)) @property def object_type(self) -> str: @@ -3102,7 +3200,11 @@ class CObject(ObjectDescription): def parse_definition(self, parser: DefinitionParser) -> ASTDeclaration: return parser.parse_declaration(self.object_type, self.objtype) - def describe_signature(self, signode: TextElement, ast: Any, options: Dict) -> None: + def parse_pre_v3_type_definition(self, parser: DefinitionParser) -> ASTDeclaration: + return parser.parse_pre_v3_type_definition() + + def describe_signature(self, signode: TextElement, ast: ASTDeclaration, + options: Dict) -> None: ast.describe_signature(signode, 'lastIsName', self.env, options) def run(self) -> List[Node]: @@ -3123,8 +3225,27 @@ class CObject(ObjectDescription): parser = DefinitionParser(sig, location=signode, config=self.env.config) try: - ast = self.parse_definition(parser) - parser.assert_end() + try: + ast = self.parse_definition(parser) + parser.assert_end() + except DefinitionError as eOrig: + if not self.env.config['c_allow_pre_v3']: + raise + if self.objtype != 'type': + raise + try: + ast = self.parse_pre_v3_type_definition(parser) + parser.assert_end() + except DefinitionError: + raise eOrig + self.object_type = ast.objectType # type: ignore + if self.env.config['c_warn_on_allowed_pre_v3']: + msg = "{}: Pre-v3 C type directive '.. c:type:: {}' converted to " \ + "'.. c:{}:: {}'." \ + "\nThe original parsing error was:\n{}" + msg = msg.format(RemovedInSphinx50Warning.__name__, + sig, ast.objectType, ast, eOrig) + logger.warning(msg, location=signode) except DefinitionError as e: logger.warning(e, location=signode) # It is easier to assume some phony name than handling the error in @@ -3132,10 +3253,11 @@ class CObject(ObjectDescription): name = _make_phony_error_name() symbol = parentSymbol.add_name(name) self.env.temp_data['c:last_symbol'] = symbol - raise ValueError + raise ValueError from e try: - symbol = parentSymbol.add_declaration(ast, docname=self.env.docname) + symbol = parentSymbol.add_declaration( + ast, docname=self.env.docname, line=self.get_source_info()[1]) # append the new declaration to the sibling list assert symbol.siblingAbove is None assert symbol.siblingBelow is None @@ -3148,7 +3270,10 @@ class CObject(ObjectDescription): # Assume we are actually in the old symbol, # instead of the newly created duplicate. self.env.temp_data['c:last_symbol'] = e.symbol - logger.warning("Duplicate declaration, %s", sig, location=signode) + msg = __("Duplicate C declaration, also defined at %s:%s.\n" + "Declaration is '.. c:%s:: %s'.") + msg = msg % (e.symbol.docname, e.symbol.line, self.display_object_type, sig) + logger.warning(msg, location=signode) if ast.objectType == 'enumerator': self._add_enumerator_to_parent(ast) @@ -3309,6 +3434,134 @@ class CNamespacePopObject(SphinxDirective): return [] +class AliasNode(nodes.Element): + def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironment" = None, + parentKey: LookupKey = None) -> None: + super().__init__() + self.sig = sig + self.maxdepth = maxdepth + assert maxdepth >= 0 + self.document = document + if env is not None: + if 'c:parent_symbol' not in env.temp_data: + root = env.domaindata['c']['root_symbol'] + env.temp_data['c:parent_symbol'] = root + self.parentKey = env.temp_data['c:parent_symbol'].get_lookup_key() + else: + assert parentKey is not None + self.parentKey = parentKey + + def copy(self) -> 'AliasNode': + return self.__class__(self.sig, self.maxdepth, self.document, + env=None, parentKey=self.parentKey) + + +class AliasTransform(SphinxTransform): + default_priority = ReferencesResolver.default_priority - 1 + + def _render_symbol(self, s: Symbol, maxdepth: int, document: Any) -> List[Node]: + nodes = [] # type: List[Node] + options = dict() # type: ignore + signode = addnodes.desc_signature('', '') + nodes.append(signode) + s.declaration.describe_signature(signode, 'markName', self.env, options) + if maxdepth == 0: + recurse = True + elif maxdepth == 1: + recurse = False + else: + maxdepth -= 1 + recurse = True + if recurse: + content = addnodes.desc_content() + desc = addnodes.desc() + content.append(desc) + desc.document = document + desc['domain'] = 'c' + # 'desctype' is a backwards compatible attribute + desc['objtype'] = desc['desctype'] = 'alias' + desc['noindex'] = True + + for sChild in s.children: + childNodes = self._render_symbol(sChild, maxdepth, document) + desc.extend(childNodes) + + if len(desc.children) != 0: + nodes.append(content) + return nodes + + def apply(self, **kwargs: Any) -> None: + for node in self.document.traverse(AliasNode): + sig = node.sig + parentKey = node.parentKey + try: + parser = DefinitionParser(sig, location=node, + config=self.env.config) + name = parser.parse_xref_object() + except DefinitionError as e: + logger.warning(e, location=node) + name = None + + if name is None: + # could not be parsed, so stop here + signode = addnodes.desc_signature(sig, '') + signode.clear() + signode += addnodes.desc_name(sig, sig) + node.replace_self(signode) + continue + + rootSymbol = self.env.domains['c'].data['root_symbol'] # type: Symbol + parentSymbol = rootSymbol.direct_lookup(parentKey) # type: Symbol + if not parentSymbol: + print("Target: ", sig) + print("ParentKey: ", parentKey) + print(rootSymbol.dump(1)) + assert parentSymbol # should be there + + s = parentSymbol.find_declaration( + name, 'any', + matchSelf=True, recurseInAnon=True) + if s is None: + signode = addnodes.desc_signature(sig, '') + node.append(signode) + signode.clear() + signode += addnodes.desc_name(sig, sig) + + logger.warning("Could not find C declaration for alias '%s'." % name, + location=node) + node.replace_self(signode) + continue + + nodes = self._render_symbol(s, maxdepth=node.maxdepth, document=node.document) + node.replace_self(nodes) + + +class CAliasObject(ObjectDescription): + option_spec = { + 'maxdepth': directives.nonnegative_int + } # type: Dict + + def run(self) -> List[Node]: + if ':' in self.name: + self.domain, self.objtype = self.name.split(':', 1) + else: + self.domain, self.objtype = '', self.name + + node = addnodes.desc() + node.document = self.state.document + node['domain'] = self.domain + # 'desctype' is a backwards compatible attribute + node['objtype'] = node['desctype'] = self.objtype + node['noindex'] = True + + self.names = [] # type: List[str] + maxdepth = self.options.get('maxdepth', 1) + signatures = self.get_signatures() + for i, sig in enumerate(signatures): + node.append(AliasNode(sig, maxdepth, self.state.document, env=self.env)) + return [node] + + class CXRefRole(XRefRole): def process_link(self, env: BuildEnvironment, refnode: Element, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]: @@ -3330,6 +3583,39 @@ class CXRefRole(XRefRole): title = title[dot + 1:] return title, target + def run(self) -> Tuple[List[Node], List[system_message]]: + if not self.env.config['c_allow_pre_v3']: + return super().run() + + text = self.text.replace('\n', ' ') + parser = DefinitionParser(text, location=self.get_source_info(), + config=self.env.config) + try: + parser.parse_xref_object() + # it succeeded, so let it through + return super().run() + except DefinitionError as eOrig: + # try as if it was an c:expr + parser.pos = 0 + try: + ast = parser.parse_expression() + except DefinitionError: + # that didn't go well, just default back + return super().run() + classes = ['xref', 'c', 'c-texpr'] + parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None) + if parentSymbol is None: + parentSymbol = self.env.domaindata['c']['root_symbol'] + signode = nodes.inline(classes=classes) + ast.describe_signature(signode, 'markType', self.env, parentSymbol) + + if self.env.config['c_warn_on_allowed_pre_v3']: + msg = "{}: Pre-v3 C type role ':c:type:`{}`' converted to ':c:expr:`{}`'." + msg += "\nThe original parsing error was:\n{}" + msg = msg.format(RemovedInSphinx50Warning.__name__, text, text, eOrig) + logger.warning(msg, location=self.get_source_info()) + return [signode], [] + class CExprRole(SphinxRole): def __init__(self, asCode: bool) -> None: @@ -3356,7 +3642,7 @@ class CExprRole(SphinxRole): location=self.get_source_info()) # see below return [self.node_type(text, text, classes=classes)], [] - parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None) + parentSymbol = self.env.temp_data.get('c:parent_symbol', None) if parentSymbol is None: parentSymbol = self.env.domaindata['c']['root_symbol'] # ...most if not all of these classes should really apply to the individual references, @@ -3371,11 +3657,18 @@ class CDomain(Domain): name = 'c' label = 'C' object_types = { - 'function': ObjType(_('function'), 'func'), - 'member': ObjType(_('member'), 'member'), - 'macro': ObjType(_('macro'), 'macro'), - 'type': ObjType(_('type'), 'type'), - 'var': ObjType(_('variable'), 'data'), + # 'identifier' is the one used for xrefs generated in signatures, not in roles + 'member': ObjType(_('member'), 'var', 'member', 'data', 'identifier'), + 'var': ObjType(_('variable'), 'var', 'member', 'data', 'identifier'), + 'function': ObjType(_('function'), 'func', 'identifier', 'type'), + 'macro': ObjType(_('macro'), 'macro', 'identifier'), + 'struct': ObjType(_('struct'), 'struct', 'identifier', 'type'), + 'union': ObjType(_('union'), 'union', 'identifier', 'type'), + 'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'), + 'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'), + 'type': ObjType(_('type'), 'identifier', 'type'), + # generated object types + 'functionParam': ObjType(_('function parameter'), 'identifier', 'var', 'member', 'data'), # noqa } directives = { @@ -3392,6 +3685,8 @@ class CDomain(Domain): 'namespace': CNamespaceObject, 'namespace-push': CNamespacePushObject, 'namespace-pop': CNamespacePopObject, + # other + 'alias': CAliasObject } roles = { 'member': CXRefRole(), @@ -3408,22 +3703,10 @@ class CDomain(Domain): 'texpr': CExprRole(asCode=False) } initial_data = { - 'root_symbol': Symbol(None, None, None, None), + 'root_symbol': Symbol(None, None, None, None, None), 'objects': {}, # fullname -> docname, node_id, objtype } # type: Dict[str, Union[Symbol, Dict[str, Tuple[str, str, str]]]] - @property - def objects(self) -> Dict[str, Tuple[str, str, str]]: - return self.data.setdefault('objects', {}) # fullname -> docname, node_id, objtype - - def note_object(self, name: str, objtype: str, node_id: str, location: Any = None) -> None: - if name in self.objects: - docname = self.objects[name][0] - logger.warning(__('Duplicate C object description of %s, ' - 'other instance in %s, use :noindex: for one of them'), - name, docname, location=location) - self.objects[name] = (self.env.docname, node_id, objtype) - def clear_doc(self, docname: str) -> None: if Symbol.debug_show_tree: print("clear_doc:", docname) @@ -3439,9 +3722,6 @@ class CDomain(Domain): print(self.data['root_symbol'].dump(1)) print("\tafter end") print("clear_doc end:", docname) - for fullname, (fn, _id, _l) in list(self.objects.items()): - if fn == docname: - del self.objects[fullname] def process_doc(self, env: BuildEnvironment, docname: str, document: nodes.document) -> None: @@ -3469,13 +3749,9 @@ class CDomain(Domain): ourObjects = self.data['objects'] for fullname, (fn, id_, objtype) in otherdata['objects'].items(): if fn in docnames: - if fullname in ourObjects: - msg = __("Duplicate declaration, also defined in '%s'.\n" - "Name of declaration is '%s'.") - msg = msg % (ourObjects[fullname], fullname) - logger.warning(msg, location=fn) - else: + if fullname not in ourObjects: ourObjects[fullname] = (fn, id_, objtype) + # no need to warn on duplicates, the symbol merge already does that def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder, typ: str, target: str, node: pending_xref, @@ -3531,14 +3807,28 @@ class CDomain(Domain): return [] def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: - for refname, (docname, node_id, objtype) in list(self.objects.items()): - yield (refname, refname, objtype, docname, node_id, 1) + rootSymbol = self.data['root_symbol'] + for symbol in rootSymbol.get_all_symbols(): + if symbol.declaration is None: + continue + assert symbol.docname + fullNestedName = symbol.get_full_nested_name() + name = str(fullNestedName).lstrip('.') + dispname = fullNestedName.get_display_string().lstrip('.') + objectType = symbol.declaration.objectType + docname = symbol.docname + newestId = symbol.declaration.get_newest_id() + yield (name, dispname, objectType, docname, newestId, 1) def setup(app: Sphinx) -> Dict[str, Any]: app.add_domain(CDomain) app.add_config_value("c_id_attributes", [], 'env') app.add_config_value("c_paren_attributes", [], 'env') + app.add_post_transform(AliasTransform) + + app.add_config_value("c_allow_pre_v3", False, 'env') + app.add_config_value("c_warn_on_allowed_pre_v3", True, 'env') return { 'version': 'builtin', diff --git a/sphinx/domains/changeset.py b/sphinx/domains/changeset.py index a07944db8..ba323b729 100644 --- a/sphinx/domains/changeset.py +++ b/sphinx/domains/changeset.py @@ -4,13 +4,12 @@ The changeset domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from collections import namedtuple -from typing import Any, Dict, List -from typing import cast +from typing import Any, Dict, List, cast from docutils import nodes from docutils.nodes import Node @@ -20,7 +19,6 @@ from sphinx.domains import Domain from sphinx.locale import _ from sphinx.util.docutils import SphinxDirective - if False: # For type annotation from sphinx.application import Sphinx diff --git a/sphinx/domains/citation.py b/sphinx/domains/citation.py index 38901867a..1ceb53037 100644 --- a/sphinx/domains/citation.py +++ b/sphinx/domains/citation.py @@ -4,12 +4,11 @@ The citation domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, List, Set, Tuple -from typing import cast +from typing import Any, Dict, List, Set, Tuple, cast from docutils import nodes from docutils.nodes import Element diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 1783db491..25e6f1421 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4,14 +4,13 @@ The C++ language domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re -from typing import ( - Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, Union, Optional -) +from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, Type, + TypeVar, Union) from docutils import nodes from docutils.nodes import Element, Node, TextElement, system_message @@ -30,19 +29,17 @@ from sphinx.roles import SphinxRole, XRefRole from sphinx.transforms import SphinxTransform from sphinx.transforms.post_transforms import ReferencesResolver from sphinx.util import logging -from sphinx.util.cfamily import ( - NoOldIdError, ASTBaseBase, ASTAttribute, verify_description_mode, StringifyTransform, - BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral, - identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re, - hex_literal_re, binary_literal_re, integers_literal_suffix_re, - float_literal_re, float_literal_suffix_re, - char_literal_re -) +from sphinx.util.cfamily import (ASTAttribute, ASTBaseBase, ASTBaseParenExprList, BaseParser, + DefinitionError, NoOldIdError, StringifyTransform, + UnsupportedMultiCharacterCharLiteral, anon_identifier_re, + binary_literal_re, char_literal_re, float_literal_re, + float_literal_suffix_re, hex_literal_re, identifier_re, + integer_literal_re, integers_literal_suffix_re, + octal_literal_re, verify_description_mode) from sphinx.util.docfields import Field, GroupedField from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import make_refnode - logger = logging.getLogger(__name__) T = TypeVar('T') @@ -140,7 +137,7 @@ T = TypeVar('T') visibility storage-class-specifier function-specifier "friend" "constexpr" "volatile" "const" trailing-type-specifier # where trailing-type-specifier can no be cv-qualifier - # Inside e.g., template paramters a strict subset is used + # Inside e.g., template parameters a strict subset is used # (see type-specifier-seq) trailing-type-specifier -> simple-type-specifier -> @@ -1595,6 +1592,15 @@ class ASTOperator(ASTBase): identifier = str(self) if mode == 'lastIsName': signode += addnodes.desc_name(identifier, identifier) + elif mode == 'markType': + targetText = prefix + identifier + templateArgs + pnode = addnodes.pending_xref('', refdomain='cpp', + reftype='identifier', + reftarget=targetText, modname=None, + classname=None) + pnode['cpp:parent_key'] = symbol.get_lookup_key() + pnode += nodes.Text(identifier) + signode += pnode else: signode += addnodes.desc_addname(identifier, identifier) @@ -1835,7 +1841,7 @@ class ASTFunctionParameter(ASTBase): # this is not part of the normal name mangling in C++ if symbol: # the anchor will be our parent - return symbol.parent.declaration.get_id(version, prefixed=None) + return symbol.parent.declaration.get_id(version, prefixed=False) # else, do the usual if self.ellipsis: return 'z' @@ -1878,7 +1884,8 @@ class ASTNoexceptSpec(ASTBase): class ASTParametersQualifiers(ASTBase): def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool, refQual: str, exceptionSpec: ASTNoexceptSpec, trailingReturn: "ASTType", - override: bool, final: bool, initializer: str) -> None: + override: bool, final: bool, attrs: List[ASTAttribute], + initializer: str) -> None: self.args = args self.volatile = volatile self.const = const @@ -1887,6 +1894,7 @@ class ASTParametersQualifiers(ASTBase): self.trailingReturn = trailingReturn self.override = override self.final = final + self.attrs = attrs self.initializer = initializer @property @@ -1946,6 +1954,9 @@ class ASTParametersQualifiers(ASTBase): res.append(' final') if self.override: res.append(' override') + for attr in self.attrs: + res.append(' ') + res.append(transform(attr)) if self.initializer: res.append(' = ') res.append(self.initializer) @@ -1987,6 +1998,9 @@ class ASTParametersQualifiers(ASTBase): _add_anno(signode, 'final') if self.override: _add_anno(signode, 'override') + for attr in self.attrs: + signode += nodes.Text(' ') + attr.describe_signature(signode) if self.initializer: _add_text(signode, '= ' + str(self.initializer)) @@ -2742,7 +2756,7 @@ class ASTPackExpansionExpr(ASTExpression): signode += nodes.Text('...') -class ASTParenExprList(ASTBase): +class ASTParenExprList(ASTBaseParenExprList): def __init__(self, exprs: List[Union[ASTExpression, ASTBracedInitList]]) -> None: self.exprs = exprs @@ -3781,6 +3795,16 @@ class Symbol: debug_lookup = False # overridden by the corresponding config value debug_show_tree = False # overridden by the corresponding config value + def __copy__(self): + assert False # shouldn't happen + + def __deepcopy__(self, memo): + if self.parent: + assert False # shouldn't happen + else: + # the domain base class makes a copy of the initial data, which is fine + return Symbol(None, None, None, None, None, None, None) + @staticmethod def debug_print(*args: Any) -> None: print(Symbol.debug_indent_string * Symbol.debug_indent, end="") @@ -3806,7 +3830,8 @@ class Symbol: def __init__(self, parent: "Symbol", identOrOp: Union[ASTIdentifier, ASTOperator], templateParams: Union[ASTTemplateParams, ASTTemplateIntroduction], - templateArgs: Any, declaration: ASTDeclaration, docname: str) -> None: + templateArgs: Any, declaration: ASTDeclaration, + docname: str, line: int) -> None: self.parent = parent # declarations in a single directive are linked together self.siblingAbove = None # type: Symbol @@ -3816,6 +3841,7 @@ class Symbol: self.templateArgs = templateArgs # identifier<templateArgs> self.declaration = declaration self.docname = docname + self.line = line self.isRedeclaration = False self._assert_invariants() @@ -3831,15 +3857,18 @@ class Symbol: # Do symbol addition after self._children has been initialised. self._add_template_and_function_params() - def _fill_empty(self, declaration: ASTDeclaration, docname: str) -> None: + def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> None: self._assert_invariants() - assert not self.declaration - assert not self.docname - assert declaration - assert docname + assert self.declaration is None + assert self.docname is None + assert self.line is None + assert declaration is not None + assert docname is not None + assert line is not None self.declaration = declaration self.declaration.symbol = self self.docname = docname + self.line = line self._assert_invariants() # and symbol addition should be done as well self._add_template_and_function_params() @@ -3863,7 +3892,7 @@ class Symbol: decl = None nne = ASTNestedNameElement(tp.get_identifier(), None) nn = ASTNestedName([nne], [False], rooted=False) - self._add_symbols(nn, [], decl, self.docname) + self._add_symbols(nn, [], decl, self.docname, self.line) # add symbols for function parameters, if any if self.declaration is not None and self.declaration.function_params is not None: for fp in self.declaration.function_params: @@ -3876,7 +3905,7 @@ class Symbol: decl = ASTDeclaration('functionParam', None, None, None, None, fp, None) assert not nn.rooted assert len(nn.names) == 1 - self._add_symbols(nn, [], decl, self.docname) + self._add_symbols(nn, [], decl, self.docname, self.line) if Symbol.debug_lookup: Symbol.debug_indent -= 1 @@ -3894,6 +3923,7 @@ class Symbol: if sChild.declaration and sChild.docname == docname: sChild.declaration = None sChild.docname = None + sChild.line = None if sChild.siblingAbove is not None: sChild.siblingAbove.siblingBelow = sChild.siblingBelow if sChild.siblingBelow is not None: @@ -3906,8 +3936,7 @@ class Symbol: def get_all_symbols(self) -> Iterator[Any]: yield self for sChild in self._children: - for s in sChild.get_all_symbols(): - yield s + yield from sChild.get_all_symbols() @property def children_recurse_anon(self) -> Generator["Symbol", None, None]: @@ -4088,7 +4117,7 @@ class Symbol: Symbol.debug_print("self:") print(self.to_string(Symbol.debug_indent + 1), end="") Symbol.debug_print("nestedName: ", nestedName) - Symbol.debug_print("templateDecls: ", templateDecls) + Symbol.debug_print("templateDecls: ", ",".join(str(t) for t in templateDecls)) Symbol.debug_print("strictTemplateParamArgLists:", strictTemplateParamArgLists) Symbol.debug_print("ancestorLookupType:", ancestorLookupType) Symbol.debug_print("templateShorthand: ", templateShorthand) @@ -4204,7 +4233,7 @@ class Symbol: identOrOp, templateParams, templateArgs) def _add_symbols(self, nestedName: ASTNestedName, templateDecls: List[Any], - declaration: ASTDeclaration, docname: str) -> "Symbol": + declaration: ASTDeclaration, docname: str, line: int) -> "Symbol": # Used for adding a whole path of symbols, where the last may or may not # be an actual declaration. @@ -4212,10 +4241,10 @@ class Symbol: Symbol.debug_indent += 1 Symbol.debug_print("_add_symbols:") Symbol.debug_indent += 1 - Symbol.debug_print("tdecls:", templateDecls) - Symbol.debug_print("nn: ", nestedName) - Symbol.debug_print("decl: ", declaration) - Symbol.debug_print("doc: ", docname) + Symbol.debug_print("tdecls:", ",".join(str(t) for t in templateDecls)) + Symbol.debug_print("nn: ", nestedName) + Symbol.debug_print("decl: ", declaration) + Symbol.debug_print("location: {}:{}".format(docname, line)) def onMissingQualifiedSymbol(parentSymbol: "Symbol", identOrOp: Union[ASTIdentifier, ASTOperator], @@ -4232,7 +4261,7 @@ class Symbol: return Symbol(parent=parentSymbol, identOrOp=identOrOp, templateParams=templateParams, templateArgs=templateArgs, declaration=None, - docname=None) + docname=None, line=None) lookupResult = self._symbol_lookup(nestedName, templateDecls, onMissingQualifiedSymbol, @@ -4253,14 +4282,14 @@ class Symbol: Symbol.debug_print("identOrOp: ", lookupResult.identOrOp) Symbol.debug_print("templateArgs: ", lookupResult.templateArgs) Symbol.debug_print("declaration: ", declaration) - Symbol.debug_print("docname: ", docname) + Symbol.debug_print("location: {}:{}".format(docname, line)) Symbol.debug_indent -= 1 symbol = Symbol(parent=lookupResult.parentSymbol, identOrOp=lookupResult.identOrOp, templateParams=lookupResult.templateParams, templateArgs=lookupResult.templateArgs, declaration=declaration, - docname=docname) + docname=docname, line=line) if Symbol.debug_lookup: Symbol.debug_indent -= 2 return symbol @@ -4273,7 +4302,7 @@ class Symbol: if not declaration: if Symbol.debug_lookup: - Symbol.debug_print("no delcaration") + Symbol.debug_print("no declaration") Symbol.debug_indent -= 2 # good, just a scope creation # TODO: what if we have more than one symbol? @@ -4309,7 +4338,7 @@ class Symbol: templateParams=lookupResult.templateParams, templateArgs=lookupResult.templateArgs, declaration=declaration, - docname=docname) + docname=docname, line=line) if Symbol.debug_lookup: Symbol.debug_print("end: creating candidate symbol") return symbol @@ -4341,6 +4370,11 @@ class Symbol: if Symbol.debug_lookup: Symbol.debug_print("candId:", candId) for symbol in withDecl: + # but all existing must be functions as well, + # otherwise we declare it to be a duplicate + if symbol.declaration.objectType != 'function': + handleDuplicateDeclaration(symbol, candSymbol) + # (not reachable) oldId = symbol.declaration.get_newest_id() if Symbol.debug_lookup: Symbol.debug_print("oldId: ", oldId) @@ -4351,7 +4385,11 @@ class Symbol: # if there is an empty symbol, fill that one if len(noDecl) == 0: if Symbol.debug_lookup: - Symbol.debug_print("no match, no empty, candSybmol is not None?:", candSymbol is not None) # NOQA + Symbol.debug_print("no match, no empty") + if candSymbol is not None: + Symbol.debug_print("result is already created candSymbol") + else: + Symbol.debug_print("result is makeCandSymbol()") Symbol.debug_indent -= 2 if candSymbol is not None: return candSymbol @@ -4372,7 +4410,7 @@ class Symbol: # .. namespace:: Test # .. namespace:: nullptr # .. class:: Test - symbol._fill_empty(declaration, docname) + symbol._fill_empty(declaration, docname, line) return symbol def merge_with(self, other: "Symbol", docnames: List[str], @@ -4451,13 +4489,15 @@ class Symbol: continue if otherChild.declaration and otherChild.docname in docnames: if not ourChild.declaration: - ourChild._fill_empty(otherChild.declaration, otherChild.docname) + ourChild._fill_empty(otherChild.declaration, + otherChild.docname, otherChild.line) elif ourChild.docname != otherChild.docname: name = str(ourChild.declaration) - msg = __("Duplicate declaration, also defined in '%s'.\n" - "Declaration is '%s'.") - msg = msg % (ourChild.docname, name) - logger.warning(msg, location=otherChild.docname) + msg = __("Duplicate C++ declaration, also defined at %s:%s.\n" + "Declaration is '.. cpp:%s:: %s'.") + msg = msg % (ourChild.docname, ourChild.line, + ourChild.declaration.directiveType, name) + logger.warning(msg, location=(otherChild.docname, otherChild.line)) else: # Both have declarations, and in the same docname. # This can apparently happen, it should be safe to @@ -4481,23 +4521,25 @@ class Symbol: else: templateDecls = [] res = self._add_symbols(nestedName, templateDecls, - declaration=None, docname=None) + declaration=None, docname=None, line=None) if Symbol.debug_lookup: Symbol.debug_indent -= 1 return res - def add_declaration(self, declaration: ASTDeclaration, docname: str) -> "Symbol": + def add_declaration(self, declaration: ASTDeclaration, + docname: str, line: int) -> "Symbol": if Symbol.debug_lookup: Symbol.debug_indent += 1 Symbol.debug_print("add_declaration:") - assert declaration - assert docname + assert declaration is not None + assert docname is not None + assert line is not None nestedName = declaration.name if declaration.templatePrefix: templateDecls = declaration.templatePrefix.templates else: templateDecls = [] - res = self._add_symbols(nestedName, templateDecls, declaration, docname) + res = self._add_symbols(nestedName, templateDecls, declaration, docname, line) if Symbol.debug_lookup: Symbol.debug_indent -= 1 return res @@ -4692,7 +4734,8 @@ class Symbol: templateParams=lookupResult.templateParams, templateArgs=lookupResult.templateArgs, declaration=declaration, - docname='fakeDocnameForQuery') + docname='fakeDocnameForQuery', + line=42) queryId = declaration.get_newest_id() for symbol in symbols: if symbol.declaration is None: @@ -4882,7 +4925,7 @@ class DefinitionParser(BaseParser): raise self._make_multi_error([ (eFold, "If fold expression"), (eExpr, "If parenthesized expression") - ], "Error in fold expression or parenthesized expression.") + ], "Error in fold expression or parenthesized expression.") from eExpr return ASTParenExpr(res) # now it definitely is a fold expression if self.skip_string(')'): @@ -5066,7 +5109,7 @@ class DefinitionParser(BaseParser): errors = [] errors.append((eType, "If type")) errors.append((eExpr, "If expression")) - raise self._make_multi_error(errors, header) + raise self._make_multi_error(errors, header) from eExpr else: # a primary expression or a type pos = self.pos try: @@ -5093,7 +5136,7 @@ class DefinitionParser(BaseParser): errors = [] errors.append((eOuter, "If primary expression")) errors.append((eInner, "If type")) - raise self._make_multi_error(errors, header) + raise self._make_multi_error(errors, header) from eInner # and now parse postfixes postFixes = [] # type: List[ASTPostfixOp] @@ -5253,7 +5296,8 @@ class DefinitionParser(BaseParser): errs = [] errs.append((exCast, "If type cast expression")) errs.append((exUnary, "If unary expression")) - raise self._make_multi_error(errs, "Error in cast expression.") + raise self._make_multi_error(errs, + "Error in cast expression.") from exUnary else: return self._parse_unary_expression() @@ -5504,7 +5548,7 @@ class DefinitionParser(BaseParser): self.pos = pos prevErrors.append((e, "If non-type argument")) header = "Error in parsing template argument list." - raise self._make_multi_error(prevErrors, header) + raise self._make_multi_error(prevErrors, header) from e if parsedEnd: assert not parsedComma break @@ -5697,6 +5741,13 @@ class DefinitionParser(BaseParser): override = self.skip_word_and_ws( 'override') # they can be permuted + attrs = [] + while True: + attr = self._parse_attribute() + if attr is None: + break + attrs.append(attr) + self.skip_ws() initializer = None if self.skip_string('='): @@ -5713,7 +5764,7 @@ class DefinitionParser(BaseParser): return ASTParametersQualifiers( args, volatile, const, refQual, exceptionSpec, trailingReturn, - override, final, initializer) + override, final, attrs, initializer) def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple: """Just parse the simple ones.""" @@ -5949,7 +6000,7 @@ class DefinitionParser(BaseParser): self.pos = pos prevErrors.append((exNoPtrParen, "If parenthesis in noptr-declarator")) header = "Error in declarator" - raise self._make_multi_error(prevErrors, header) + raise self._make_multi_error(prevErrors, header) from exNoPtrParen if typed: # pointer to member pos = self.pos try: @@ -5988,7 +6039,7 @@ class DefinitionParser(BaseParser): self.pos = pos prevErrors.append((e, "If declarator-id")) header = "Error in declarator or parameters-and-qualifiers" - raise self._make_multi_error(prevErrors, header) + raise self._make_multi_error(prevErrors, header) from e def _parse_initializer(self, outer: str = None, allowFallback: bool = True ) -> ASTInitializer: @@ -6096,7 +6147,7 @@ class DefinitionParser(BaseParser): header = "Error when parsing function declaration." else: assert False - raise self._make_multi_error(prevErrors, header) + raise self._make_multi_error(prevErrors, header) from exTyped else: # For testing purposes. # do it again to get the proper traceback (how do you @@ -6163,7 +6214,7 @@ class DefinitionParser(BaseParser): errs.append((eType, "If default template argument is a type")) msg = "Error in non-type template parameter" msg += " or constrained template parameter." - raise self._make_multi_error(errs, msg) + raise self._make_multi_error(errs, msg) from eType def _parse_type_using(self) -> ASTTypeUsing: name = self._parse_nested_name() @@ -6238,23 +6289,19 @@ class DefinitionParser(BaseParser): # ========================================================================== - def _parse_template_parameter_list(self) -> ASTTemplateParams: - # only: '<' parameter-list '>' - # we assume that 'template' has just been parsed - templateParams = [] # type: List[ASTTemplateParam] + def _parse_template_paramter(self) -> ASTTemplateParam: self.skip_ws() - if not self.skip_string("<"): - self.fail("Expected '<' after 'template'") - prevErrors = [] - while 1: - self.skip_ws() - if self.skip_word('template'): - # declare a tenplate template parameter - nestedParams = self._parse_template_parameter_list() - else: - nestedParams = None - self.skip_ws() + if self.skip_word('template'): + # declare a tenplate template parameter + nestedParams = self._parse_template_parameter_list() + else: + nestedParams = None + + pos = self.pos + try: + # Unconstrained type parameter or template type parameter key = None + self.skip_ws() if self.skip_word_and_ws('typename'): key = 'typename' elif self.skip_word_and_ws('class'): @@ -6262,52 +6309,79 @@ class DefinitionParser(BaseParser): elif nestedParams: self.fail("Expected 'typename' or 'class' after " "template template parameter list.") - if key: - # declare a type or template type parameter - self.skip_ws() - parameterPack = self.skip_string('...') - self.skip_ws() - if self.match(identifier_re): - identifier = ASTIdentifier(self.matched_text) - else: - identifier = None - self.skip_ws() - if not parameterPack and self.skip_string('='): - default = self._parse_type(named=False, outer=None) - else: - default = None - data = ASTTemplateKeyParamPackIdDefault(key, identifier, - parameterPack, default) - if nestedParams: - # template type - templateParams.append( - ASTTemplateParamTemplateType(nestedParams, data)) - else: - # type - templateParams.append(ASTTemplateParamType(data)) else: - # declare a non-type parameter, or constrained type parameter - pos = self.pos - try: - param = self._parse_type_with_init('maybe', 'templateParam') - templateParams.append(ASTTemplateParamNonType(param)) - except DefinitionError as e: - msg = "If non-type template parameter or constrained template parameter" - prevErrors.append((e, msg)) - self.pos = pos + self.fail("Expected 'typename' or 'class' in tbe " + "beginning of template type parameter.") + self.skip_ws() + parameterPack = self.skip_string('...') + self.skip_ws() + if self.match(identifier_re): + identifier = ASTIdentifier(self.matched_text) + else: + identifier = None + self.skip_ws() + if not parameterPack and self.skip_string('='): + default = self._parse_type(named=False, outer=None) + else: + default = None + if self.current_char not in ',>': + self.fail('Expected "," or ">" after (template) type parameter.') + data = ASTTemplateKeyParamPackIdDefault(key, identifier, + parameterPack, default) + if nestedParams: + return ASTTemplateParamTemplateType(nestedParams, data) + else: + return ASTTemplateParamType(data) + except DefinitionError as eType: + if nestedParams: + raise + try: + # non-type parameter or constrained type parameter + self.pos = pos + param = self._parse_type_with_init('maybe', 'templateParam') + return ASTTemplateParamNonType(param) + except DefinitionError as eNonType: + self.pos = pos + header = "Error when parsing template parameter." + errs = [] + errs.append( + (eType, "If unconstrained type parameter or template type parameter")) + errs.append( + (eNonType, "If constrained type parameter or non-type parameter")) + raise self._make_multi_error(errs, header) + + def _parse_template_parameter_list(self) -> ASTTemplateParams: + # only: '<' parameter-list '>' + # we assume that 'template' has just been parsed + templateParams = [] # type: List[ASTTemplateParam] + self.skip_ws() + if not self.skip_string("<"): + self.fail("Expected '<' after 'template'") + while 1: + pos = self.pos + err = None + try: + param = self._parse_template_paramter() + templateParams.append(param) + except DefinitionError as eParam: + self.pos = pos + err = eParam self.skip_ws() if self.skip_string('>'): return ASTTemplateParams(templateParams) elif self.skip_string(','): - prevErrors = [] continue else: header = "Error in template parameter list." + errs = [] + if err: + errs.append((err, "If parameter")) try: - self.fail('Expected "=", ",", or ">".') + self.fail('Expected "," or ">".') except DefinitionError as e: - prevErrors.append((e, "")) - raise self._make_multi_error(prevErrors, header) + errs.append((e, "If no parameter")) + print(errs) + raise self._make_multi_error(errs, header) def _parse_template_introduction(self) -> ASTTemplateIntroduction: pos = self.pos @@ -6510,7 +6584,7 @@ class DefinitionParser(BaseParser): self.pos = pos prevErrors.append((e, "If type alias or template alias")) header = "Error in type declaration." - raise self._make_multi_error(prevErrors, header) + raise self._make_multi_error(prevErrors, header) from e elif objectType == 'concept': declaration = self._parse_concept() elif objectType == 'member': @@ -6576,7 +6650,7 @@ class DefinitionParser(BaseParser): errs.append((e1, "If shorthand ref")) errs.append((e2, "If full function ref")) msg = "Error in cross-reference." - raise self._make_multi_error(errs, msg) + raise self._make_multi_error(errs, msg) from e2 def parse_expression(self) -> Union[ASTExpression, ASTType]: pos = self.pos @@ -6597,7 +6671,7 @@ class DefinitionParser(BaseParser): errs = [] errs.append((exExpr, "If expression")) errs.append((exType, "If type")) - raise self._make_multi_error(errs, header) + raise self._make_multi_error(errs, header) from exType def _make_phony_error_name() -> ASTNestedName: @@ -6605,7 +6679,7 @@ def _make_phony_error_name() -> ASTNestedName: return ASTNestedName([nne], [False], rooted=False) -class CPPObject(ObjectDescription): +class CPPObject(ObjectDescription[ASTDeclaration]): """Description of a C++ language object.""" doc_field_types = [ @@ -6622,8 +6696,10 @@ class CPPObject(ObjectDescription): names=('returns', 'return')), ] - option_spec = dict(ObjectDescription.option_spec) - option_spec['tparam-line-spec'] = directives.flag + option_spec = { + 'noindexentry': directives.flag, + 'tparam-line-spec': directives.flag, + } def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None: assert ast.objectType == 'enumerator' @@ -6665,7 +6741,7 @@ class CPPObject(ObjectDescription): Symbol(parent=targetSymbol, identOrOp=symbol.identOrOp, templateParams=None, templateArgs=None, declaration=declClone, - docname=self.env.docname) + docname=self.env.docname, line=self.get_source_info()[1]) def add_target_and_index(self, ast: ASTDeclaration, sig: str, signode: TextElement) -> None: @@ -6698,7 +6774,7 @@ class CPPObject(ObjectDescription): if decl.objectType == 'concept': isInConcept = True break - if not isInConcept: + if not isInConcept and 'noindexentry' not in self.options: strippedName = name for prefix in self.env.config.cpp_index_common_prefix: if name.startswith(prefix): @@ -6762,10 +6838,12 @@ class CPPObject(ObjectDescription): parentSymbol = env.temp_data['cpp:parent_symbol'] parentDecl = parentSymbol.declaration if parentDecl is not None and parentDecl.objectType == 'function': - logger.warning("C++ declarations inside functions are not supported." + - " Parent function is " + - str(parentSymbol.get_full_nested_name()), - location=self.get_source_info()) + msg = "C++ declarations inside functions are not supported." \ + " Parent function: {}\nDirective name: {}\nDirective arg: {}" + logger.warning(msg.format( + str(parentSymbol.get_full_nested_name()), + self.name, self.arguments[0] + ), location=self.get_source_info()) name = _make_phony_error_name() symbol = parentSymbol.add_name(name) env.temp_data['cpp:last_symbol'] = symbol @@ -6777,7 +6855,7 @@ class CPPObject(ObjectDescription): return super().run() def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration: - parentSymbol = self.env.temp_data['cpp:parent_symbol'] + parentSymbol = self.env.temp_data['cpp:parent_symbol'] # type: Symbol parser = DefinitionParser(sig, location=signode, config=self.env.config) try: @@ -6790,10 +6868,11 @@ class CPPObject(ObjectDescription): name = _make_phony_error_name() symbol = parentSymbol.add_name(name) self.env.temp_data['cpp:last_symbol'] = symbol - raise ValueError + raise ValueError from e try: - symbol = parentSymbol.add_declaration(ast, docname=self.env.docname) + symbol = parentSymbol.add_declaration( + ast, docname=self.env.docname, line=self.get_source_info()[1]) # append the new declaration to the sibling list assert symbol.siblingAbove is None assert symbol.siblingBelow is None @@ -6806,7 +6885,11 @@ class CPPObject(ObjectDescription): # Assume we are actually in the old symbol, # instead of the newly created duplicate. self.env.temp_data['cpp:last_symbol'] = e.symbol - logger.warning("Duplicate declaration, %s", sig, location=signode) + msg = __("Duplicate C++ declaration, also defined at %s:%s.\n" + "Declaration is '.. cpp:%s:: %s'.") + msg = msg % (e.symbol.docname, e.symbol.line, + self.display_object_type, sig) + logger.warning(msg, location=signode) if ast.objectType == 'enumerator': self._add_enumerator_to_parent(ast) @@ -6976,8 +7059,8 @@ class AliasNode(nodes.Element): assert parentKey is not None self.parentKey = parentKey - def copy(self: T) -> T: - return self.__class__(self.sig, env=None, parentKey=self.parentKey) # type: ignore + def copy(self) -> 'AliasNode': + return self.__class__(self.sig, env=None, parentKey=self.parentKey) class AliasTransform(SphinxTransform): @@ -7081,7 +7164,6 @@ class CPPAliasObject(ObjectDescription): node['domain'] = self.domain # 'desctype' is a backwards compatible attribute node['objtype'] = node['desctype'] = self.objtype - node['noindex'] = True self.names = [] # type: List[str] signatures = self.get_signatures() @@ -7178,14 +7260,18 @@ class CPPDomain(Domain): name = 'cpp' label = 'C++' object_types = { - 'class': ObjType(_('class'), 'class', 'type', 'identifier'), - 'union': ObjType(_('union'), 'union', 'type', 'identifier'), - 'function': ObjType(_('function'), 'function', 'func', 'type', 'identifier'), - 'member': ObjType(_('member'), 'member', 'var'), - 'type': ObjType(_('type'), 'type', 'identifier'), - 'concept': ObjType(_('concept'), 'concept', 'identifier'), - 'enum': ObjType(_('enum'), 'enum', 'type', 'identifier'), - 'enumerator': ObjType(_('enumerator'), 'enumerator') + 'class': ObjType(_('class'), 'class', 'struct', 'identifier', 'type'), + 'union': ObjType(_('union'), 'union', 'identifier', 'type'), + 'function': ObjType(_('function'), 'func', 'identifier', 'type'), + 'member': ObjType(_('member'), 'member', 'var', 'identifier'), + 'type': ObjType(_('type'), 'identifier', 'type'), + 'concept': ObjType(_('concept'), 'concept', 'identifier'), + 'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'), + 'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'), + # generated object types + 'functionParam': ObjType(_('function parameter'), 'identifier', 'member', 'var'), # noqa + 'templateParam': ObjType(_('template parameter'), + 'identifier', 'class', 'struct', 'union', 'member', 'var', 'type'), # noqa } directives = { @@ -7225,7 +7311,7 @@ class CPPDomain(Domain): 'texpr': CPPExprRole(asCode=False) } initial_data = { - 'root_symbol': Symbol(None, None, None, None, None, None), + 'root_symbol': Symbol(None, None, None, None, None, None, None), 'names': {} # full name for indexing -> docname } @@ -7273,13 +7359,9 @@ class CPPDomain(Domain): ourNames = self.data['names'] for name, docname in otherdata['names'].items(): if docname in docnames: - if name in ourNames: - msg = __("Duplicate declaration, also defined in '%s'.\n" - "Name of declaration is '%s'.") - msg = msg % (ourNames[name], name) - logger.warning(msg, location=docname) - else: + if name not in ourNames: ourNames[name] = docname + # no need to warn on duplicates, the symbol merge already does that if Symbol.debug_show_tree: print("\tresult:") print(self.data['root_symbol'].dump(1)) @@ -7366,30 +7448,19 @@ class CPPDomain(Domain): if typ.startswith('cpp:'): typ = typ[4:] - origTyp = typ - if typ == 'func': - typ = 'function' - if typ == 'struct': - typ = 'class' declTyp = s.declaration.objectType def checkType() -> bool: - if typ == 'any' or typ == 'identifier': + if typ == 'any': return True - if declTyp == 'templateParam': - # TODO: perhaps this should be strengthened one day - return True - if declTyp == 'functionParam': - if typ == 'var' or typ == 'member': - return True objtypes = self.objtypes_for_role(typ) if objtypes: return declTyp in objtypes - print("Type is %s (originally: %s), declType is %s" % (typ, origTyp, declTyp)) + print("Type is %s, declaration type is %s" % (typ, declTyp)) assert False if not checkType(): logger.warning("cpp:%s targets a %s (%s).", - origTyp, s.declaration.objectType, + typ, s.declaration.objectType, s.get_full_nested_name(), location=node) @@ -7419,10 +7490,10 @@ class CPPDomain(Domain): if env.config.add_function_parentheses and typ == 'any': addParen += 1 # and now this stuff for operator() - if (env.config.add_function_parentheses and typ == 'function' and + if (env.config.add_function_parentheses and typ == 'func' and title.endswith('operator()')): addParen += 1 - if ((typ == 'any' or typ == 'function') and + if ((typ == 'any' or typ == 'func') and title.endswith('operator') and displayName.endswith('operator()')): addParen += 1 @@ -7431,7 +7502,7 @@ class CPPDomain(Domain): if env.config.add_function_parentheses: if typ == 'any' and displayName.endswith('()'): addParen += 1 - elif typ == 'function': + elif typ == 'func': if title.endswith('()') and not displayName.endswith('()'): title = title[:-2] else: diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index 18a256bac..4a91d6ad1 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -4,7 +4,7 @@ The index domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -17,8 +17,7 @@ from docutils.parsers.rst import directives from sphinx import addnodes from sphinx.domains import Domain from sphinx.environment import BuildEnvironment -from sphinx.util import logging -from sphinx.util import split_index_msg +from sphinx.util import logging, split_index_msg from sphinx.util.docutils import ReferenceRole, SphinxDirective from sphinx.util.nodes import process_index_entry diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index d510d7903..f612fb914 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -4,12 +4,11 @@ The JavaScript domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, Iterator, List, Tuple -from typing import cast +from typing import Any, Dict, Iterator, List, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node @@ -30,11 +29,10 @@ from sphinx.util.docfields import Field, GroupedField, TypedField from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import make_id, make_refnode - logger = logging.getLogger(__name__) -class JSObject(ObjectDescription): +class JSObject(ObjectDescription[Tuple[str, str]]): """ Description of a JavaScript object. """ @@ -49,6 +47,11 @@ class JSObject(ObjectDescription): #: based on directive nesting allow_nesting = False + option_spec = { + 'noindex': directives.flag, + 'noindexentry': directives.flag, + } + def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]: """Breaks down construct signatures @@ -120,9 +123,10 @@ class JSObject(ObjectDescription): domain = cast(JavaScriptDomain, self.env.get_domain('js')) domain.note_object(fullname, self.objtype, node_id, location=signode) - indextext = self.get_index_text(mod_name, name_obj) - if indextext: - self.indexnode['entries'].append(('single', indextext, node_id, '', None)) + if 'noindexentry' not in self.options: + indextext = self.get_index_text(mod_name, name_obj) + if indextext: + self.indexnode['entries'].append(('single', indextext, node_id, '', None)) def get_index_text(self, objectname: str, name_obj: Tuple[str, str]) -> str: name, obj = name_obj @@ -143,7 +147,7 @@ class JSObject(ObjectDescription): :py:class:`JSObject` represents JavaScript language constructs. For constructs that are nestable, this method will build up a stack of the - nesting heirarchy so that it can be later de-nested correctly, in + nesting hierarchy so that it can be later de-nested correctly, in :py:meth:`after_content`. For constructs that aren't nestable, the stack is bypassed, and instead diff --git a/sphinx/domains/math.py b/sphinx/domains/math.py index e77bd0ed7..248a7a2a6 100644 --- a/sphinx/domains/math.py +++ b/sphinx/domains/math.py @@ -4,7 +4,7 @@ The math domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,8 +12,7 @@ import warnings from typing import Any, Dict, Iterable, List, Tuple from docutils import nodes -from docutils.nodes import Element, Node, system_message -from docutils.nodes import make_id +from docutils.nodes import Element, Node, make_id, system_message from sphinx.addnodes import pending_xref from sphinx.deprecation import RemovedInSphinx40Warning @@ -158,8 +157,11 @@ class MathDomain(Domain): targets = [eq for eq in self.equations.values() if eq[0] == docname] return len(targets) + 1 - def has_equations(self) -> bool: - return any(self.data['has_equations'].values()) + def has_equations(self, docname: str = None) -> bool: + if docname: + return self.data['has_equations'].get(docname, False) + else: + return any(self.data['has_equations'].values()) def setup(app: "Sphinx") -> Dict[str, Any]: diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index fc1136ae2..c2af9886f 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -4,33 +4,34 @@ The Python domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import builtins import inspect import re +import sys import typing import warnings from inspect import Parameter -from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Tuple -from typing import cast +from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node from docutils.parsers.rst import directives from sphinx import addnodes -from sphinx.addnodes import pending_xref, desc_signature +from sphinx.addnodes import desc_signature, pending_xref from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.directives import ObjectDescription -from sphinx.domains import Domain, ObjType, Index, IndexEntry +from sphinx.domains import Domain, Index, IndexEntry, ObjType from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ -from sphinx.pycode.ast import ast, parse as ast_parse +from sphinx.pycode.ast import ast +from sphinx.pycode.ast import parse as ast_parse from sphinx.roles import XRefRole from sphinx.util import logging from sphinx.util.docfields import Field, GroupedField, TypedField @@ -77,18 +78,24 @@ ModuleEntry = NamedTuple('ModuleEntry', [('docname', str), ('deprecated', bool)]) -def type_to_xref(text: str) -> addnodes.pending_xref: +def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xref: """Convert a type string to a cross reference node.""" if text == 'None': reftype = 'obj' else: reftype = 'class' + if env: + kwargs = {'py:module': env.ref_context.get('py:module'), + 'py:class': env.ref_context.get('py:class')} + else: + kwargs = {} + return pending_xref('', nodes.Text(text), - refdomain='py', reftype=reftype, reftarget=text) + refdomain='py', reftype=reftype, reftarget=text, **kwargs) -def _parse_annotation(annotation: str) -> List[Node]: +def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Node]: """Parse type annotation.""" def unparse(node: ast.AST) -> List[Node]: if isinstance(node, ast.Attribute): @@ -128,20 +135,37 @@ def _parse_annotation(annotation: str) -> List[Node]: return result else: + if sys.version_info >= (3, 6): + if isinstance(node, ast.Constant): + if node.value is Ellipsis: + return [addnodes.desc_sig_punctuation('', "...")] + else: + return [nodes.Text(node.value)] + + if sys.version_info < (3, 8): + if isinstance(node, ast.Ellipsis): + return [addnodes.desc_sig_punctuation('', "...")] + elif isinstance(node, ast.NameConstant): + return [nodes.Text(node.value)] + raise SyntaxError # unsupported syntax + if env is None: + warnings.warn("The env parameter for _parse_annotation becomes required now.", + RemovedInSphinx50Warning, stacklevel=2) + try: tree = ast_parse(annotation) result = unparse(tree) for i, node in enumerate(result): if isinstance(node, nodes.Text): - result[i] = type_to_xref(str(node)) + result[i] = type_to_xref(str(node), env) return result except SyntaxError: - return [type_to_xref(annotation)] + return [type_to_xref(annotation, env)] -def _parse_arglist(arglist: str) -> addnodes.desc_parameterlist: +def _parse_arglist(arglist: str, env: BuildEnvironment = None) -> addnodes.desc_parameterlist: """Parse a list of arguments using AST parser""" params = addnodes.desc_parameterlist(arglist) sig = signature_from_str('(%s)' % arglist) @@ -167,7 +191,7 @@ def _parse_arglist(arglist: str) -> addnodes.desc_parameterlist: node += addnodes.desc_sig_name('', param.name) if param.annotation is not param.empty: - children = _parse_annotation(param.annotation) + children = _parse_annotation(param.annotation, env) node += addnodes.desc_sig_punctuation('', ':') node += nodes.Text(' ') node += addnodes.desc_sig_name('', '', *children) # type: ignore @@ -248,6 +272,8 @@ class PyXrefMixin: result = super().make_xref(rolename, domain, target, # type: ignore innernode, contnode, env) result['refspecific'] = True + result['py:module'] = env.ref_context.get('py:module') + result['py:class'] = env.ref_context.get('py:class') if target.startswith(('.', '~')): prefix, result['reftarget'] = target[0], target[1:] if prefix == '.': @@ -308,7 +334,7 @@ class PyTypedField(PyXrefMixin, TypedField): return super().make_xref(rolename, domain, target, innernode, contnode, env) -class PyObject(ObjectDescription): +class PyObject(ObjectDescription[Tuple[str, str]]): """ Description of a general Python object. @@ -317,6 +343,7 @@ class PyObject(ObjectDescription): """ option_spec = { 'noindex': directives.flag, + 'noindexentry': directives.flag, 'module': directives.unchanged, 'annotation': directives.unchanged, } @@ -414,7 +441,7 @@ class PyObject(ObjectDescription): signode += addnodes.desc_name(name, name) if arglist: try: - signode += _parse_arglist(arglist) + signode += _parse_arglist(arglist, self.env) except SyntaxError: # fallback to parse arglist original parser. # it supports to represent optional arguments (ex. "func(foo [, bar])") @@ -429,7 +456,7 @@ class PyObject(ObjectDescription): signode += addnodes.desc_parameterlist() if retann: - children = _parse_annotation(retann) + children = _parse_annotation(retann, self.env) signode += addnodes.desc_returns(retann, '', *children) anno = self.options.get('annotation') @@ -459,16 +486,17 @@ class PyObject(ObjectDescription): domain = cast(PythonDomain, self.env.get_domain('py')) domain.note_object(fullname, self.objtype, node_id, location=signode) - indextext = self.get_index_text(modname, name_cls) - if indextext: - self.indexnode['entries'].append(('single', indextext, node_id, '', None)) + if 'noindexentry' not in self.options: + indextext = self.get_index_text(modname, name_cls) + if indextext: + self.indexnode['entries'].append(('single', indextext, node_id, '', None)) def before_content(self) -> None: """Handle object nesting before content :py:class:`PyObject` represents Python language constructs. For constructs that are nestable, such as a Python classes, this method will - build up a stack of the nesting heirarchy so that it can be later + build up a stack of the nesting hierarchy so that it can be later de-nested correctly, in :py:meth:`after_content`. For constructs that aren't nestable, the stack is bypassed, and instead @@ -576,16 +604,17 @@ class PyFunction(PyObject): def add_target_and_index(self, name_cls: Tuple[str, str], sig: str, signode: desc_signature) -> None: super().add_target_and_index(name_cls, sig, signode) - modname = self.options.get('module', self.env.ref_context.get('py:module')) - node_id = signode['ids'][0] + if 'noindexentry' not in self.options: + modname = self.options.get('module', self.env.ref_context.get('py:module')) + node_id = signode['ids'][0] - name, cls = name_cls - if modname: - text = _('%s() (in module %s)') % (name, modname) - self.indexnode['entries'].append(('single', text, node_id, '', None)) - else: - text = '%s; %s()' % (pairindextypes['builtin'], name) - self.indexnode['entries'].append(('pair', text, node_id, '', None)) + name, cls = name_cls + if modname: + text = _('%s() (in module %s)') % (name, modname) + self.indexnode['entries'].append(('single', text, node_id, '', None)) + else: + text = '%s; %s()' % (pairindextypes['builtin'], name) + self.indexnode['entries'].append(('pair', text, node_id, '', None)) def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: # add index in own add_target_and_index() instead. @@ -623,7 +652,8 @@ class PyVariable(PyObject): typ = self.options.get('type') if typ: - signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), type_to_xref(typ)) + annotations = _parse_annotation(typ, self.env) + signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), *annotations) value = self.options.get('value') if value: @@ -868,7 +898,8 @@ class PyAttribute(PyObject): typ = self.options.get('type') if typ: - signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), type_to_xref(typ)) + annotations = _parse_annotation(typ, self.env) + signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), *annotations) value = self.options.get('value') if value: diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index e25b31936..07bf46b75 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -4,13 +4,12 @@ The reStructuredText domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re -from typing import Any, Dict, Iterator, List, Tuple -from typing import cast +from typing import Any, Dict, Iterator, List, Tuple, cast from docutils.nodes import Element from docutils.parsers.rst import directives @@ -27,13 +26,12 @@ from sphinx.roles import XRefRole from sphinx.util import logging from sphinx.util.nodes import make_id, make_refnode - logger = logging.getLogger(__name__) dir_sig_re = re.compile(r'\.\. (.+?)::(.*)$') -class ReSTMarkup(ObjectDescription): +class ReSTMarkup(ObjectDescription[str]): """ Description of generic reST markup. """ diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 6dc597022..5b1dab2b8 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -4,7 +4,7 @@ The standard domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,8 +12,7 @@ import re import unicodedata import warnings from copy import copy -from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union -from typing import cast +from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast from docutils import nodes from docutils.nodes import Element, Node, system_message @@ -27,7 +26,7 @@ from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType from sphinx.locale import _, __ from sphinx.roles import XRefRole -from sphinx.util import ws_re, logging, docname_join +from sphinx.util import docname_join, logging, ws_re from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import clean_astext, make_id, make_refnode from sphinx.util.typing import RoleFunction @@ -35,6 +34,7 @@ from sphinx.util.typing import RoleFunction if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.environment import BuildEnvironment @@ -45,10 +45,10 @@ logger = logging.getLogger(__name__) # RE for option descriptions option_desc_re = re.compile(r'((?:/|--|-|\+)?[^\s=]+)(=?\s*.*)') # RE for grammar tokens -token_re = re.compile(r'`(\w+)`', re.U) +token_re = re.compile(r'`((~?\w*:)?\w+)`', re.U) -class GenericObject(ObjectDescription): +class GenericObject(ObjectDescription[str]): """ A generic x-ref directive registered with Sphinx.add_object_type(). """ @@ -178,7 +178,7 @@ class Target(SphinxDirective): return self.name + '-' + name -class Cmdoption(ObjectDescription): +class Cmdoption(ObjectDescription[str]): """ Description of a command-line option (.. option). """ @@ -197,6 +197,11 @@ class Cmdoption(ObjectDescription): location=signode) continue optname, args = m.groups() + if optname.endswith('[') and args.endswith(']'): + # optional value surrounded by brackets (ex. foo[=bar]) + optname = optname[:-1] + args = '[' + args + if count: signode += addnodes.desc_addname(', ', ', ') signode += addnodes.desc_name(optname, optname) @@ -223,6 +228,11 @@ class Cmdoption(ObjectDescription): node_id = make_id(self.env, self.state.document, prefix, optname) signode['ids'].append(node_id) + old_node_id = self.make_old_id(prefix, optname) + if old_node_id not in self.state.document.ids and \ + old_node_id not in signode['ids']: + signode['ids'].append(old_node_id) + self.state.document.note_explicit_target(signode) domain = cast(StandardDomain, self.env.get_domain('std')) @@ -239,6 +249,14 @@ class Cmdoption(ObjectDescription): entry = '; '.join([descr, option]) self.indexnode['entries'].append(('pair', entry, signode['ids'][0], '', None)) + def make_old_id(self, prefix: str, optname: str) -> str: + """Generate old styled node_id for cmdoption. + + .. note:: Old Styled node_id was used until Sphinx-3.0. + This will be removed in Sphinx-5.0. + """ + return nodes.make_id(prefix + '-' + optname) + class Program(SphinxDirective): """ @@ -446,9 +464,23 @@ def token_xrefs(text: str, productionGroup: str = '') -> List[Node]: if m.start() > pos: txt = text[pos:m.start()] retnodes.append(nodes.Text(txt, txt)) - refnode = pending_xref(m.group(1), reftype='token', refdomain='std', - reftarget=productionGroup + m.group(1)) - refnode += nodes.literal(m.group(1), m.group(1), classes=['xref']) + token = m.group(1) + if ':' in token: + if token[0] == '~': + _, title = token.split(':') + target = token[1:] + elif token[0] == ':': + title = token[1:] + target = title + else: + title = token + target = token + else: + title = token + target = productionGroup + token + refnode = pending_xref(title, reftype='token', refdomain='std', + reftarget=target) + refnode += nodes.literal(token, title, classes=['xref']) retnodes.append(refnode) pos = m.end() if pos < len(text): @@ -487,7 +519,8 @@ class ProductionList(SphinxDirective): except ValueError: break subnode = addnodes.production(rule) - subnode['tokenname'] = name.strip() + name = name.strip() + subnode['tokenname'] = name if subnode['tokenname']: prefix = 'grammar-token-%s' % productionGroup node_id = make_id(self.env, self.state.document, prefix, name) @@ -596,8 +629,6 @@ class StandardDomain(Domain): dangling_warnings = { 'term': 'term not in glossary: %(target)s', - 'ref': 'undefined label: %(target)s (if the link has no caption ' - 'the label must precede a section header)', 'numref': 'undefined label: %(target)s', 'keyword': 'unknown keyword: %(target)s', 'doc': 'unknown document: %(target)s', @@ -728,9 +759,11 @@ class StandardDomain(Domain): name, env.doc2path(self.labels[name][0]), location=node) self.anonlabels[name] = docname, labelid - if node.tagname in ('section', 'rubric'): + if node.tagname == 'section': title = cast(nodes.title, node[0]) sectname = clean_astext(title) + elif node.tagname == 'rubric': + sectname = clean_astext(node) elif self.is_enumerable_node(node): sectname = self.get_numfig_title(node) if not sectname: @@ -840,8 +873,9 @@ class StandardDomain(Domain): if fignumber is None: return contnode except ValueError: - logger.warning(__("no number is assigned for %s: %s"), figtype, labelid, - location=node) + logger.warning(__("Failed to create a cross reference. Any number is not " + "assigned: %s"), + labelid, location=node) return contnode try: @@ -1061,10 +1095,10 @@ class StandardDomain(Domain): try: figure_id = target_node['ids'][0] return env.toc_fignumbers[docname][figtype][figure_id] - except (KeyError, IndexError): + except (KeyError, IndexError) as exc: # target_node is found, but fignumber is not assigned. # Maybe it is defined in orphaned document. - raise ValueError + raise ValueError from exc def get_full_qualified_name(self, node: Element) -> str: if node.get('reftype') == 'option': @@ -1093,8 +1127,23 @@ class StandardDomain(Domain): RemovedInSphinx40Warning, stacklevel=2) +def warn_missing_reference(app: "Sphinx", domain: Domain, node: pending_xref) -> bool: + if (domain and domain.name != 'std') or node['reftype'] != 'ref': + return None + else: + target = node['reftarget'] + if target not in domain.anonlabels: # type: ignore + msg = __('undefined label: %s') + else: + msg = __('Failed to create a cross reference. A title or caption not found: %s') + + logger.warning(msg % target, location=node, type='ref', subtype=node['reftype']) + return True + + def setup(app: "Sphinx") -> Dict[str, Any]: app.add_domain(StandardDomain) + app.connect('warn-missing-reference', warn_missing_reference) return { 'version': 'builtin', diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 6584ac6d8..af3e2b8d5 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -4,18 +4,18 @@ Global creation environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import pickle +import posixpath import warnings from collections import defaultdict from copy import copy from os import path -from typing import Any, Callable, Dict, Generator, Iterator, List, Set, Tuple, Union -from typing import cast +from typing import Any, Callable, Dict, Generator, Iterator, List, Set, Tuple, Union, cast from docutils import nodes from docutils.nodes import Node @@ -25,13 +25,12 @@ from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.domains import Domain from sphinx.environment.adapters.toctree import TocTree -from sphinx.errors import SphinxError, BuildEnvironmentError, DocumentError, ExtensionError +from sphinx.errors import BuildEnvironmentError, DocumentError, ExtensionError, SphinxError from sphinx.events import EventManager from sphinx.locale import __ from sphinx.project import Project from sphinx.transforms import SphinxTransformer -from sphinx.util import DownloadFiles, FilenameUniqDict -from sphinx.util import logging +from sphinx.util import DownloadFiles, FilenameUniqDict, logging from sphinx.util.docutils import LoggingReporter from sphinx.util.i18n import CatalogRepository, docname_to_domain from sphinx.util.nodes import is_translatable @@ -358,9 +357,9 @@ class BuildEnvironment: docdir = path.dirname(self.doc2path(docname or self.docname, base=None)) rel_fn = path.join(docdir, filename) - # the path.abspath() might seem redundant, but otherwise artifacts - # such as ".." will remain in the path - return rel_fn, path.abspath(path.join(self.srcdir, rel_fn)) + + return (posixpath.normpath(rel_fn), + path.normpath(path.join(self.srcdir, rel_fn))) @property def found_docs(self) -> Set[str]: @@ -387,13 +386,14 @@ class BuildEnvironment: # add catalog mo file dependency repo = CatalogRepository(self.srcdir, self.config.locale_dirs, self.config.language, self.config.source_encoding) + mo_paths = {c.domain: c.mo_path for c in repo.catalogs} for docname in self.found_docs: domain = docname_to_domain(docname, self.config.gettext_compact) - for catalog in repo.catalogs: - if catalog.domain == domain: - self.dependencies[docname].add(catalog.mo_path) + if domain in mo_paths: + self.dependencies[docname].add(mo_paths[domain]) except OSError as exc: - raise DocumentError(__('Failed to scan documents in %s: %r') % (self.srcdir, exc)) + raise DocumentError(__('Failed to scan documents in %s: %r') % + (self.srcdir, exc)) from exc def get_outdated_files(self, config_changed: bool) -> Tuple[Set[str], Set[str], Set[str]]: """Return (added, changed, removed) sets.""" @@ -511,8 +511,8 @@ class BuildEnvironment: """ try: return self.domains[domainname] - except KeyError: - raise ExtensionError(__('Domain %r is not registered') % domainname) + except KeyError as exc: + raise ExtensionError(__('Domain %r is not registered') % domainname) from exc # --------- RESOLVING REFERENCES AND TOCTREES ------------------------------ @@ -593,7 +593,9 @@ class BuildEnvironment: def traverse_toctree(parent: str, docname: str) -> Iterator[Tuple[str, str]]: if parent == docname: - logger.warning(__('self referenced toctree found. Ignored.'), location=docname) + logger.warning(__('self referenced toctree found. Ignored.'), + location=docname, type='toc', + subtype='circular') return # traverse toctree by pre-order diff --git a/sphinx/environment/adapters/__init__.py b/sphinx/environment/adapters/__init__.py index c9cde6364..1e763cb01 100644 --- a/sphinx/environment/adapters/__init__.py +++ b/sphinx/environment/adapters/__init__.py @@ -4,6 +4,6 @@ Sphinx environment adapters - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/adapters/asset.py b/sphinx/environment/adapters/asset.py index 38e4eb064..f16a5f7d3 100644 --- a/sphinx/environment/adapters/asset.py +++ b/sphinx/environment/adapters/asset.py @@ -4,7 +4,7 @@ Assets adapter for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/adapters/indexentries.py b/sphinx/environment/adapters/indexentries.py index 5af213932..e662bfe4a 100644 --- a/sphinx/environment/adapters/indexentries.py +++ b/sphinx/environment/adapters/indexentries.py @@ -4,23 +4,21 @@ Index entries adapters for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re import unicodedata from itertools import groupby -from typing import Any, Dict, Pattern, List, Tuple -from typing import cast +from typing import Any, Dict, List, Pattern, Tuple, cast from sphinx.builders import Builder from sphinx.domains.index import IndexDomain from sphinx.environment import BuildEnvironment from sphinx.errors import NoUri from sphinx.locale import _, __ -from sphinx.util import split_into, logging - +from sphinx.util import logging, split_into logger = logging.getLogger(__name__) @@ -98,9 +96,8 @@ class IndexEntries: for subentry in indexentry[1].values(): subentry[0].sort(key=keyfunc0) # type: ignore - # sort the index entries; put all symbols at the front, even those - # following the letters in ASCII, this is where the chr(127) comes from - def keyfunc(entry: Tuple[str, List]) -> Tuple[str, str]: + # sort the index entries + def keyfunc(entry: Tuple[str, List]) -> Tuple[Tuple[int, str], str]: key, (void, void, category_key) = entry if category_key: # using specified category key to sort @@ -108,11 +105,16 @@ class IndexEntries: lckey = unicodedata.normalize('NFD', key.lower()) if lckey.startswith('\N{RIGHT-TO-LEFT MARK}'): lckey = lckey[1:] + if lckey[0:1].isalpha() or lckey.startswith('_'): - lckey = chr(127) + lckey + # put non-symbol characters at the folloing group (1) + sortkey = (1, lckey) + else: + # put symbols at the front of the index (0) + sortkey = (0, lckey) # ensure a determinstic order *within* letters by also sorting on # the entry itself - return (lckey, entry[0]) + return (sortkey, entry[0]) newlist = sorted(new.items(), key=keyfunc) if group_entries: diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py index 9a1ef73d4..93555d172 100644 --- a/sphinx/environment/adapters/toctree.py +++ b/sphinx/environment/adapters/toctree.py @@ -4,19 +4,18 @@ Toctree adapter for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Iterable, List -from typing import cast +from typing import Any, Iterable, List, cast from docutils import nodes from docutils.nodes import Element, Node from sphinx import addnodes from sphinx.locale import __ -from sphinx.util import url_re, logging +from sphinx.util import logging, url_re from sphinx.util.matching import Matcher from sphinx.util.nodes import clean_astext, process_only_nodes @@ -321,8 +320,10 @@ class TocTree: toctrees = [] # type: List[Element] if 'includehidden' not in kwargs: kwargs['includehidden'] = True - if 'maxdepth' not in kwargs: + if 'maxdepth' not in kwargs or not kwargs['maxdepth']: kwargs['maxdepth'] = 0 + else: + kwargs['maxdepth'] = int(kwargs['maxdepth']) kwargs['collapse'] = collapse for toctreenode in doctree.traverse(addnodes.toctree): toctree = self.resolve(docname, builder, toctreenode, prune=True, **kwargs) diff --git a/sphinx/environment/collectors/__init__.py b/sphinx/environment/collectors/__init__.py index 53e3a1c72..4b7ac3472 100644 --- a/sphinx/environment/collectors/__init__.py +++ b/sphinx/environment/collectors/__init__.py @@ -4,7 +4,7 @@ The data collector components for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/asset.py b/sphinx/environment/collectors/asset.py index 06a0d5198..b8d7ae4c0 100644 --- a/sphinx/environment/collectors/asset.py +++ b/sphinx/environment/collectors/asset.py @@ -4,7 +4,7 @@ The image collector for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -26,7 +26,6 @@ from sphinx.util import logging from sphinx.util.i18n import get_image_filename_for_language, search_image_for_language from sphinx.util.images import guess_mimetype - logger = logging.getLogger(__name__) @@ -58,17 +57,13 @@ class ImageCollector(EnvironmentCollector): elif imguri.find('://') != -1: candidates['?'] = imguri continue - rel_imgpath, full_imgpath = app.env.relfn2path(imguri, docname) - if app.config.language: - # substitute figures (ex. foo.png -> foo.en.png) - i18n_full_imgpath = search_image_for_language(full_imgpath, app.env) - if i18n_full_imgpath != full_imgpath: - full_imgpath = i18n_full_imgpath - rel_imgpath = relative_path(path.join(app.srcdir, 'dummy'), - i18n_full_imgpath) - # set imgpath as default URI - node['uri'] = rel_imgpath - if rel_imgpath.endswith(os.extsep + '*'): + + if imguri.endswith(os.extsep + '*'): + # Update `node['uri']` to a relative path from srcdir + # from a relative path from current document. + rel_imgpath, full_imgpath = app.env.relfn2path(imguri, docname) + node['uri'] = rel_imgpath + if app.config.language: # Search language-specific figures at first i18n_imguri = get_image_filename_for_language(imguri, app.env) @@ -77,7 +72,15 @@ class ImageCollector(EnvironmentCollector): self.collect_candidates(app.env, full_imgpath, candidates, node) else: - candidates['*'] = rel_imgpath + if app.config.language: + # substitute imguri by figure_language_filename + # (ex. foo.png -> foo.en.png) + imguri = search_image_for_language(imguri, app.env) + + # Update `node['uri']` to a relative path from srcdir + # from a relative path from current document. + node['uri'], _ = app.env.relfn2path(imguri, docname) + candidates['*'] = node['uri'] # map image paths to unique image names (so that they can be put # into a single directory) diff --git a/sphinx/environment/collectors/dependencies.py b/sphinx/environment/collectors/dependencies.py index cc0af037e..cd8de918f 100644 --- a/sphinx/environment/collectors/dependencies.py +++ b/sphinx/environment/collectors/dependencies.py @@ -4,7 +4,7 @@ The dependencies collector components for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/indexentries.py b/sphinx/environment/collectors/indexentries.py index a4c0450d2..351cdc2de 100644 --- a/sphinx/environment/collectors/indexentries.py +++ b/sphinx/environment/collectors/indexentries.py @@ -4,7 +4,7 @@ Index entries collector for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -18,8 +18,7 @@ from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.environment import BuildEnvironment from sphinx.environment.collectors import EnvironmentCollector -from sphinx.util import split_index_msg, logging - +from sphinx.util import logging, split_index_msg logger = logging.getLogger(__name__) diff --git a/sphinx/environment/collectors/metadata.py b/sphinx/environment/collectors/metadata.py index bcff1f273..7b3628c9a 100644 --- a/sphinx/environment/collectors/metadata.py +++ b/sphinx/environment/collectors/metadata.py @@ -4,12 +4,11 @@ The metadata collector components for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, List, Set -from typing import cast +from typing import Any, Dict, List, Set, cast from docutils import nodes diff --git a/sphinx/environment/collectors/title.py b/sphinx/environment/collectors/title.py index 10cd6c5b0..5225155e8 100644 --- a/sphinx/environment/collectors/title.py +++ b/sphinx/environment/collectors/title.py @@ -4,7 +4,7 @@ The title collector components for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/toctree.py b/sphinx/environment/collectors/toctree.py index e168bd9c4..772451c56 100644 --- a/sphinx/environment/collectors/toctree.py +++ b/sphinx/environment/collectors/toctree.py @@ -4,12 +4,11 @@ Toctree collector for sphinx.environment. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, List, Set, Tuple, TypeVar -from typing import cast +from typing import Any, Dict, List, Set, Tuple, TypeVar, cast from docutils import nodes from docutils.nodes import Element, Node @@ -21,7 +20,7 @@ from sphinx.environment.adapters.toctree import TocTree from sphinx.environment.collectors import EnvironmentCollector from sphinx.locale import __ from sphinx.transforms import SphinxContentsFilter -from sphinx.util import url_re, logging +from sphinx.util import logging, url_re if False: # For type annotation @@ -224,6 +223,10 @@ class TocTreeCollector(EnvironmentCollector): def get_figtype(node: Node) -> str: for domain in env.domains.values(): figtype = domain.get_enumerable_node_type(node) + if domain.name == 'std' and not domain.get_numfig_title(node): # type: ignore + # Skip if uncaptioned node + continue + if figtype: return figtype diff --git a/sphinx/errors.py b/sphinx/errors.py index d9a83712c..c632d8dbc 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -5,7 +5,7 @@ Contains SphinxError and a few subclasses (in an extra module to avoid circular import problems). - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/events.py b/sphinx/events.py index 0911dfaaa..806a6e55d 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -6,7 +6,7 @@ Gracefully adapted from the TextPress system by Armin. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -23,6 +23,7 @@ from sphinx.util import logging if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx @@ -46,10 +47,9 @@ core_events = { 'doctree-read': 'the doctree before being pickled', 'env-merge-info': 'env, read docnames, other env instance', 'missing-reference': 'env, node, contnode', + 'warn-missing-reference': 'domain, node', 'doctree-resolved': 'doctree, docname', 'env-updated': 'env', - 'html-collect-pages': 'builder', - 'html-page-context': 'pagename, context, doctree or None', 'build-finished': 'exception', } @@ -115,7 +115,7 @@ class EventManager: raise except Exception as exc: raise ExtensionError(__("Handler %r for event %r threw an exception") % - (listener.handler, name)) from exc + (listener.handler, name), exc) from exc return results def emit_firstresult(self, name: str, *args: Any, diff --git a/sphinx/ext/__init__.py b/sphinx/ext/__init__.py index 4f4fd0127..80c185741 100644 --- a/sphinx/ext/__init__.py +++ b/sphinx/ext/__init__.py @@ -4,6 +4,6 @@ Contains Sphinx features not activated by default. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index b01604617..ebbdadbe8 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -10,7 +10,7 @@ Copyright 2008 Société des arts technologiques (SAT), https://sat.qc.ca/ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -24,7 +24,7 @@ from copy import copy from fnmatch import fnmatch from importlib.machinery import EXTENSION_SUFFIXES from os import path -from typing import Any, List, Tuple +from typing import Any, Generator, List, Tuple import sphinx.locale from sphinx import __display_version__, package_dir @@ -264,14 +264,46 @@ def is_skipped_module(filename: str, opts: Any, excludes: List[str]) -> bool: return False +def walk(rootpath: str, excludes: List[str], opts: Any + ) -> Generator[Tuple[str, List[str], List[str]], None, None]: + """Walk through the directory and list files and subdirectories up.""" + followlinks = getattr(opts, 'followlinks', False) + includeprivate = getattr(opts, 'includeprivate', False) + + for root, subs, files in os.walk(rootpath, followlinks=followlinks): + # document only Python module files (that aren't excluded) + files = sorted(f for f in files + if f.endswith(PY_SUFFIXES) and + not is_excluded(path.join(root, f), excludes)) + + # remove hidden ('.') and private ('_') directories, as well as + # excluded dirs + if includeprivate: + exclude_prefixes = ('.',) # type: Tuple[str, ...] + else: + exclude_prefixes = ('.', '_') + + subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and + not is_excluded(path.join(root, sub), excludes)) + + yield root, subs, files + + +def has_child_module(rootpath: str, excludes: List[str], opts: Any) -> bool: + """Check the given directory contains child modules at least one.""" + for root, subs, files in walk(rootpath, excludes, opts): + if files: + return True + + return False + + def recurse_tree(rootpath: str, excludes: List[str], opts: Any, user_template_dir: str = None) -> List[str]: """ Look for every file in the directory tree and create the corresponding ReST files. """ - followlinks = getattr(opts, 'followlinks', False) - includeprivate = getattr(opts, 'includeprivate', False) implicit_namespaces = getattr(opts, 'implicit_namespaces', False) # check if the base directory is a package and get its name @@ -282,48 +314,36 @@ def recurse_tree(rootpath: str, excludes: List[str], opts: Any, root_package = None toplevels = [] - for root, subs, files in os.walk(rootpath, followlinks=followlinks): - # document only Python module files (that aren't excluded) - py_files = sorted(f for f in files - if f.endswith(PY_SUFFIXES) and - not is_excluded(path.join(root, f), excludes)) - is_pkg = is_packagedir(None, py_files) + for root, subs, files in walk(rootpath, excludes, opts): + is_pkg = is_packagedir(None, files) is_namespace = not is_pkg and implicit_namespaces if is_pkg: - for f in py_files[:]: + for f in files[:]: if is_initpy(f): - py_files.remove(f) - py_files.insert(0, f) + files.remove(f) + files.insert(0, f) elif root != rootpath: # only accept non-package at toplevel unless using implicit namespaces if not implicit_namespaces: del subs[:] continue - # remove hidden ('.') and private ('_') directories, as well as - # excluded dirs - if includeprivate: - exclude_prefixes = ('.',) # type: Tuple[str, ...] - else: - exclude_prefixes = ('.', '_') - subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and - not is_excluded(path.join(root, sub), excludes)) if is_pkg or is_namespace: # we are in a package with something to document - if subs or len(py_files) > 1 or not is_skipped_package(root, opts): + if subs or len(files) > 1 or not is_skipped_package(root, opts): subpackage = root[len(rootpath):].lstrip(path.sep).\ replace(path.sep, '.') # if this is not a namespace or # a namespace and there is something there to document - if not is_namespace or len(py_files) > 0: + if not is_namespace or has_child_module(root, excludes, opts): create_package_file(root, root_package, subpackage, - py_files, opts, subs, is_namespace, excludes, + files, opts, subs, is_namespace, excludes, user_template_dir) toplevels.append(module_join(root_package, subpackage)) else: # if we are at the root level, we don't require it to be a package assert root == rootpath and root_package is None - for py_file in py_files: + for py_file in files: if not is_skipped_module(path.join(rootpath, py_file), opts, excludes): module = py_file.split('.')[0] create_module_file(root_package, module, opts, user_template_dir) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index e247d3bd2..83c7d28c4 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -6,40 +6,41 @@ the doctree, thus avoiding duplication between docstrings and documentation for those who like elaborate docstrings. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -import importlib import re import warnings from inspect import Parameter, Signature from types import ModuleType -from typing import ( - Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, Union -) +from typing import (Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, + TypeVar, Union) from docutils.statemachine import StringList import sphinx from sphinx.application import Sphinx -from sphinx.config import Config, ENUM -from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning +from sphinx.config import ENUM, Config +from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning, + RemovedInSphinx60Warning) from sphinx.environment import BuildEnvironment -from sphinx.ext.autodoc.importer import import_object, get_module_members, get_object_members -from sphinx.ext.autodoc.mock import mock +from sphinx.ext.autodoc.importer import (get_class_members, get_object_members, import_module, + import_object) +from sphinx.ext.autodoc.mock import ismock, mock from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer, PycodeError -from sphinx.util import inspect -from sphinx.util import logging -from sphinx.util import split_full_qualified_name +from sphinx.util import inspect, logging from sphinx.util.docstrings import extract_metadata, prepare_docstring -from sphinx.util.inspect import getdoc, object_description, safe_getattr, stringify_signature +from sphinx.util.inspect import (evaluate_signature, getdoc, object_description, safe_getattr, + stringify_signature) +from sphinx.util.typing import get_type_hints, restify from sphinx.util.typing import stringify as stringify_typehint if False: # For type annotation from typing import Type # NOQA # for python3.5.1 + from sphinx.ext.autodoc.directive import DocumenterBridge @@ -60,13 +61,29 @@ py_ext_sig_re = re.compile( (?:\s* -> \s* (.*))? # return annotation )? $ # and nothing more ''', re.VERBOSE) +special_member_re = re.compile(r'^__\S+__$') def identity(x: Any) -> Any: return x -ALL = object() +class _All: + """A special value for :*-members: that matches to any member.""" + + def __contains__(self, item: Any) -> bool: + return True + + +class _Empty: + """A special value for :exclude-members: that never matches to any member.""" + + def __contains__(self, item: Any) -> bool: + return False + + +ALL = _All() +EMPTY = _Empty() UNINITIALIZED_ATTR = object() INSTANCEATTR = object() SLOTSATTR = object() @@ -74,21 +91,33 @@ SLOTSATTR = object() def members_option(arg: Any) -> Union[object, List[str]]: """Used to convert the :members: option to auto directives.""" - if arg is None or arg is True: + if arg in (None, True): return ALL - return [x.strip() for x in arg.split(',') if x.strip()] + elif arg is False: + return None + else: + return [x.strip() for x in arg.split(',') if x.strip()] def members_set_option(arg: Any) -> Union[object, Set[str]]: """Used to convert the :members: option to auto directives.""" + warnings.warn("members_set_option() is deprecated.", + RemovedInSphinx50Warning, stacklevel=2) if arg is None: return ALL return {x.strip() for x in arg.split(',') if x.strip()} +def exclude_members_option(arg: Any) -> Union[object, Set[str]]: + """Used to convert the :exclude-members: option.""" + if arg in (None, True): + return EMPTY + return {x.strip() for x in arg.split(',') if x.strip()} + + def inherited_members_option(arg: Any) -> Union[object, Set[str]]: """Used to convert the :members: option to auto directives.""" - if arg is None: + if arg in (None, True): return 'object' else: return arg @@ -96,7 +125,7 @@ def inherited_members_option(arg: Any) -> Union[object, Set[str]]: def member_order_option(arg: Any) -> Optional[str]: """Used to convert the :members: option to auto directives.""" - if arg is None: + if arg in (None, True): return None elif arg in ('alphabetical', 'bysource', 'groupwise'): return arg @@ -108,7 +137,7 @@ SUPPRESS = object() def annotation_option(arg: Any) -> Any: - if arg is None: + if arg in (None, True): # suppress showing the representation of the object return SUPPRESS else: @@ -124,6 +153,8 @@ def bool_option(arg: Any) -> bool: def merge_special_members_option(options: Dict) -> None: """Merge :special-members: option to :members: option.""" + warnings.warn("merge_special_members_option() is deprecated.", + RemovedInSphinx50Warning, stacklevel=2) if 'special-members' in options and options['special-members'] is not ALL: if options.get('members') is ALL: pass @@ -135,6 +166,20 @@ def merge_special_members_option(options: Dict) -> None: options['members'] = options['special-members'] +def merge_members_option(options: Dict) -> None: + """Merge :*-members: option to the :members: option.""" + if options.get('members') is ALL: + # merging is not needed when members: ALL + return + + members = options.setdefault('members', []) + for key in {'private-members', 'special-members'}: + if key in options and options[key] not in (ALL, None): + for member in options[key]: + if member not in members: + members.append(member) + + # Some useful event listener factories for autodoc-process-docstring. def cut_lines(pre: int, post: int = 0, what: str = None) -> Callable: @@ -212,6 +257,35 @@ class Options(dict): return None +class ObjectMember(tuple): + """A member of object. + + This is used for the result of `Documenter.get_object_members()` to + represent each member of the object. + + .. Note:: + + An instance of this class behaves as a tuple of (name, object) + for compatibility to old Sphinx. The behavior will be dropped + in the future. Therefore extensions should not use the tuple + interface. + """ + + def __new__(cls, name: str, obj: Any, **kwargs: Any) -> Any: + return super().__new__(cls, (name, obj)) # type: ignore + + def __init__(self, name: str, obj: Any, docstring: Optional[str] = None, + class_: Any = None, skipped: bool = False) -> None: + self.__name__ = name + self.object = obj + self.docstring = docstring + self.skipped = skipped + self.class_ = class_ + + +ObjectMembers = Union[List[ObjectMember], List[Tuple[str, Any]]] + + class Documenter: """ A Documenter knows how to autodocument a single object type. When @@ -253,6 +327,7 @@ class Documenter: def __init__(self, directive: "DocumenterBridge", name: str, indent: str = '') -> None: self.directive = directive + self.config = directive.env.config self.env = directive.env # type: BuildEnvironment self.options = directive.genopt self.name = name @@ -323,7 +398,7 @@ class Documenter: modname = None parents = [] - with mock(self.env.config.autodoc_mock_imports): + with mock(self.config.autodoc_mock_imports): self.modname, self.objpath = self.resolve_name(modname, parents, path, base) if not self.modname: @@ -335,23 +410,26 @@ class Documenter: ('.' + '.'.join(self.objpath) if self.objpath else '') return True - def import_object(self) -> bool: + def import_object(self, raiseerror: bool = False) -> bool: """Import the object given by *self.modname* and *self.objpath* and set it as *self.object*. Returns True if successful, False if an error occurred. """ - with mock(self.env.config.autodoc_mock_imports): + with mock(self.config.autodoc_mock_imports): try: ret = import_object(self.modname, self.objpath, self.objtype, attrgetter=self.get_attr, - warningiserror=self.env.config.autodoc_warningiserror) + warningiserror=self.config.autodoc_warningiserror) self.module, self.parent, self.object_name, self.object = ret return True except ImportError as exc: - logger.warning(exc.args[0], type='autodoc', subtype='import_object') - self.env.note_reread() - return False + if raiseerror: + raise + else: + logger.warning(exc.args[0], type='autodoc', subtype='import_object') + self.env.note_reread() + return False def get_real_modname(self) -> str: """Get the real module name of an object to document. @@ -422,9 +500,9 @@ class Documenter: if matched: args = matched.group(1) retann = matched.group(2) - except Exception: - logger.warning(__('error while formatting arguments for %s:') % - self.fullname, type='autodoc', exc_info=True) + except Exception as exc: + logger.warning(__('error while formatting arguments for %s: %s'), + self.fullname, exc, type='autodoc') args = None result = self.env.events.emit_firstresult('autodoc-process-signature', @@ -460,8 +538,12 @@ class Documenter: # etc. don't support a prepended module name self.add_line(' :module: %s' % self.modname, sourcename) - def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: - """Decode and return lines of the docstring(s) for the object.""" + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: + """Decode and return lines of the docstring(s) for the object. + + When it returns None value, autodoc-process-docstring will not be called for this + object. + """ if encoding is not None: warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." % self.__class__.__name__, @@ -470,8 +552,7 @@ class Documenter: warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated." % self.__class__.__name__, RemovedInSphinx50Warning, stacklevel=2) - docstring = getdoc(self.object, self.get_attr, - self.env.config.autodoc_inherit_docstrings, + docstring = getdoc(self.object, self.get_attr, self.config.autodoc_inherit_docstrings, self.parent, self.object_name) if docstring: tab_width = self.directive.state.document.settings.tab_width @@ -486,15 +567,35 @@ class Documenter: self.env.app.emit('autodoc-process-docstring', self.objtype, self.fullname, self.object, self.options, docstringlines) + + if docstringlines and docstringlines[-1] != '': + # append a blank line to the end of the docstring + docstringlines.append('') + yield from docstringlines def get_sourcename(self) -> str: + if (getattr(self.object, '__module__', None) and + getattr(self.object, '__qualname__', None)): + # Get the correct location of docstring from self.object + # to support inherited methods + fullname = '%s.%s' % (self.object.__module__, self.object.__qualname__) + else: + fullname = self.fullname + if self.analyzer: - return '%s:docstring of %s' % (self.analyzer.srcname, self.fullname) - return 'docstring of %s' % self.fullname + return '%s:docstring of %s' % (self.analyzer.srcname, fullname) + else: + return 'docstring of %s' % fullname - def add_content(self, more_content: Any, no_docstring: bool = False) -> None: + def add_content(self, more_content: Optional[StringList], no_docstring: bool = False + ) -> None: """Add content from docstrings, attribute documentation and user.""" + if no_docstring: + warnings.warn("The 'no_docstring' argument to %s.add_content() is deprecated." + % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + # set sourcename and add content from attribute documentation sourcename = self.get_sourcename() if self.analyzer: @@ -513,33 +614,39 @@ class Documenter: # add content from docstrings if not no_docstring: docstrings = self.get_doc() - if not docstrings: - # append at least a dummy docstring, so that the event - # autodoc-process-docstring is fired and can add some - # content if desired - docstrings.append([]) - for i, line in enumerate(self.process_doc(docstrings)): - self.add_line(line, sourcename, i) + if docstrings is None: + # Do not call autodoc-process-docstring on get_doc() returns None. + pass + else: + if not docstrings: + # append at least a dummy docstring, so that the event + # autodoc-process-docstring is fired and can add some + # content if desired + docstrings.append([]) + for i, line in enumerate(self.process_doc(docstrings)): + self.add_line(line, sourcename, i) # add additional content (e.g. from document), if present if more_content: for line, src in zip(more_content.data, more_content.items): self.add_line(line, src[0], src[1]) - def get_object_members(self, want_all: bool) -> Tuple[bool, List[Tuple[str, Any]]]: + def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]: """Return `(members_check_module, members)` where `members` is a list of `(membername, member)` pairs of the members of *self.object*. If *want_all* is True, return all members. Else, only return those members given by *self.options.members* (which may also be none). """ + warnings.warn('The implementation of Documenter.get_object_members() will be ' + 'removed from Sphinx-6.0.', RemovedInSphinx60Warning) members = get_object_members(self.object, self.objpath, self.get_attr, self.analyzer) if not want_all: if not self.options.members: - return False, [] + return False, [] # type: ignore # specific members given selected = [] - for name in self.options.members: + for name in self.options.members: # type: str if name in members: selected.append((name, members[name].value)) else: @@ -552,7 +659,7 @@ class Documenter: return False, [(m.name, m.value) for m in members.values() if m.directly_defined] - def filter_members(self, members: List[Tuple[str, Any]], want_all: bool + def filter_members(self, members: ObjectMembers, want_all: bool ) -> List[Tuple[str, Any, bool]]: """Filter the given member list. @@ -567,7 +674,7 @@ class Documenter: The user can override the skipping decision by connecting to the ``autodoc-skip-member`` event. """ - def is_filtered_inherited_member(name: str) -> bool: + def is_filtered_inherited_member(name: str, obj: Any) -> bool: if inspect.isclass(self.object): for cls in self.object.__mro__: if cls.__name__ == self.options.inherited_members and cls != self.object: @@ -575,6 +682,10 @@ class Documenter: return True elif name in cls.__dict__: return False + elif name in self.get_attr(cls, '__annotations__', {}): + return False + elif isinstance(obj, ObjectMember) and obj.class_ is cls: + return False return False @@ -589,14 +700,15 @@ class Documenter: attr_docs = {} # process members and determine which to skip - for (membername, member) in members: + for obj in members: + membername, member = obj # if isattr is True, the member is documented as an attribute if member is INSTANCEATTR: isattr = True else: isattr = False - doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings, + doc = getdoc(member, self.get_attr, self.config.autodoc_inherit_docstrings, self.parent, self.object_name) if not isinstance(doc, str): # Ignore non-string __doc__ @@ -609,6 +721,11 @@ class Documenter: cls_doc = self.get_attr(cls, '__doc__', None) if cls_doc == doc: doc = None + + if isinstance(obj, ObjectMember) and obj.docstring: + # hack for ClassDocumenter to inject docstring via ObjectMember + doc = obj.docstring + has_doc = bool(doc) metadata = extract_metadata(doc) @@ -622,41 +739,55 @@ class Documenter: isprivate = membername.startswith('_') keep = False - if safe_getattr(member, '__sphinx_mock__', False): + if ismock(member): # mocked module or object pass - elif want_all and membername.startswith('__') and \ - membername.endswith('__') and len(membername) > 4: + elif self.options.exclude_members and membername in self.options.exclude_members: + # remove members given by exclude-members + keep = False + elif want_all and special_member_re.match(membername): # special __methods__ - if self.options.special_members is ALL: + if self.options.special_members and membername in self.options.special_members: if membername == '__doc__': keep = False - elif is_filtered_inherited_member(membername): + elif is_filtered_inherited_member(membername, obj): keep = False else: keep = has_doc or self.options.undoc_members - elif self.options.special_members: - if membername in self.options.special_members: - keep = has_doc or self.options.undoc_members + else: + keep = False elif (namespace, membername) in attr_docs: if want_all and isprivate: - # ignore members whose name starts with _ by default - keep = self.options.private_members + if self.options.private_members is None: + keep = False + else: + keep = membername in self.options.private_members else: # keep documented attributes keep = True isattr = True elif want_all and isprivate: - # ignore members whose name starts with _ by default - keep = self.options.private_members and \ - (has_doc or self.options.undoc_members) + if has_doc or self.options.undoc_members: + if self.options.private_members is None: + keep = False + elif is_filtered_inherited_member(membername, obj): + keep = False + else: + keep = membername in self.options.private_members + else: + keep = False else: - if self.options.members is ALL and is_filtered_inherited_member(membername): + if (self.options.members is ALL and + is_filtered_inherited_member(membername, obj)): keep = False else: # ignore undocumented members if :undoc-members: is not given keep = has_doc or self.options.undoc_members + if isinstance(obj, ObjectMember) and obj.skipped: + # forcedly skipped member (ex. a module attribute not defined in __all__) + keep = False + # give the user a chance to decide whether this member # should be skipped if self.env.app: @@ -694,16 +825,6 @@ class Documenter: # find out which members are documentable members_check_module, members = self.get_object_members(want_all) - # remove members given by exclude-members - if self.options.exclude_members: - members = [ - (membername, member) for (membername, member) in members - if ( - self.options.exclude_members is ALL or - membername not in self.options.exclude_members - ) - ] - # document non-skipped members memberdocumenters = [] # type: List[Tuple[Documenter, bool]] for (mname, member, isattr) in self.filter_members(members, want_all): @@ -721,7 +842,7 @@ class Documenter: documenter = classes[-1](self.directive, full_mname, self.indent) memberdocumenters.append((documenter, isattr)) - member_order = self.options.member_order or self.env.config.autodoc_member_order + member_order = self.options.member_order or self.config.autodoc_member_order memberdocumenters = self.sort_members(memberdocumenters, member_order) for documenter, isattr in memberdocumenters: @@ -758,7 +879,7 @@ class Documenter: return documenters - def generate(self, more_content: Any = None, real_modname: str = None, + def generate(self, more_content: Optional[StringList] = None, real_modname: str = None, check_module: bool = False, all_members: bool = False) -> None: """Generate reST for the object given by *self.name*, and possibly for its members. @@ -795,8 +916,8 @@ class Documenter: # parse right now, to get PycodeErrors on parsing (results will # be cached anyway) self.analyzer.find_attr_docs() - except PycodeError: - logger.debug('[autodoc] module analyzer failed:', exc_info=True) + except PycodeError as exc: + logger.debug('[autodoc] module analyzer failed: %s', exc) # no source file -- e.g. for builtin and C modules self.analyzer = None # at least add the module.__file__ as a dependency @@ -826,7 +947,12 @@ class Documenter: self.add_line('', sourcename) # format the object's signature, if any - sig = self.format_signature() + try: + sig = self.format_signature() + except Exception as exc: + logger.warning(__('error while formatting signature for %s: %s'), + self.fullname, exc, type='autodoc') + return # generate the directive header and options, if applicable self.add_directive_header(sig) @@ -855,15 +981,15 @@ class ModuleDocumenter(Documenter): 'noindex': bool_option, 'inherited-members': inherited_members_option, 'show-inheritance': bool_option, 'synopsis': identity, 'platform': identity, 'deprecated': bool_option, - 'member-order': member_order_option, 'exclude-members': members_set_option, - 'private-members': bool_option, 'special-members': members_option, + 'member-order': member_order_option, 'exclude-members': exclude_members_option, + 'private-members': members_option, 'special-members': members_option, 'imported-members': bool_option, 'ignore-module-all': bool_option } # type: Dict[str, Callable] def __init__(self, *args: Any) -> None: super().__init__(*args) - merge_special_members_option(self.options) - self.__all__ = None + merge_members_option(self.options) + self.__all__ = None # type: Optional[Sequence[str]] @classmethod def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any @@ -886,27 +1012,21 @@ class ModuleDocumenter(Documenter): type='autodoc') return ret - def import_object(self) -> Any: - def is_valid_module_all(__all__: Any) -> bool: - """Check the given *__all__* is valid for a module.""" - if (isinstance(__all__, (list, tuple)) and - all(isinstance(e, str) for e in __all__)): - return True - else: - return False - - ret = super().import_object() + def import_object(self, raiseerror: bool = False) -> bool: + ret = super().import_object(raiseerror) - if not self.options.ignore_module_all: - __all__ = getattr(self.object, '__all__', None) - if is_valid_module_all(__all__): - # valid __all__ found. copy it to self.__all__ - self.__all__ = __all__ - elif __all__: - # invalid __all__ found. - logger.warning(__('__all__ should be a list of strings, not %r ' - '(in module %s) -- ignoring __all__') % - (__all__, self.fullname), type='autodoc') + try: + if not self.options.ignore_module_all: + self.__all__ = inspect.getall(self.object) + except AttributeError as exc: + # __all__ raises an error. + logger.warning(__('%s.__all__ raises an error. Ignored: %r'), + (self.fullname, exc), type='autodoc') + except ValueError as exc: + # invalid __all__ found. + logger.warning(__('__all__ should be a list of strings, not %r ' + '(in module %s) -- ignoring __all__') % + (exc.args[0], self.fullname), type='autodoc') return ret @@ -923,28 +1043,59 @@ class ModuleDocumenter(Documenter): if self.options.deprecated: self.add_line(' :deprecated:', sourcename) - def get_object_members(self, want_all: bool) -> Tuple[bool, List[Tuple[str, Any]]]: + def get_module_members(self) -> Dict[str, ObjectMember]: + """Get members of target module.""" + if self.analyzer: + attr_docs = self.analyzer.attr_docs + else: + attr_docs = {} + + members = {} # type: Dict[str, ObjectMember] + for name in dir(self.object): + try: + value = safe_getattr(self.object, name, None) + docstring = attr_docs.get(('', name), []) + members[name] = ObjectMember(name, value, docstring="\n".join(docstring)) + except AttributeError: + continue + + # annotation only member (ex. attr: int) + try: + for name in inspect.getannotations(self.object): + if name not in members: + docstring = attr_docs.get(('', name), []) + members[name] = ObjectMember(name, INSTANCEATTR, + docstring="\n".join(docstring)) + except AttributeError: + pass + + return members + + def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]: + members = self.get_module_members() if want_all: - if self.__all__: - memberlist = self.__all__ - else: + if self.__all__ is None: # for implicit module members, check __module__ to avoid # documenting imported objects - return True, get_module_members(self.object) + return True, list(members.values()) + else: + for member in members.values(): + if member.__name__ not in self.__all__: + member.skipped = True + + return False, list(members.values()) else: memberlist = self.options.members or [] - ret = [] - for mname in memberlist: - try: - ret.append((mname, safe_getattr(self.object, mname))) - except AttributeError: - logger.warning( - __('missing attribute mentioned in :members: or __all__: ' - 'module %s, attribute %s') % - (safe_getattr(self.object, '__name__', '???'), mname), - type='autodoc' - ) - return False, ret + ret = [] + for name in memberlist: + if name in members: + ret.append(members[name]) + else: + logger.warning(__('missing attribute mentioned in :members: option: ' + 'module %s, attribute %s') % + (safe_getattr(self.object, '__name__', '???'), name), + type='autodoc') + return False, ret def sort_members(self, documenters: List[Tuple["Documenter", bool]], order: str) -> List[Tuple["Documenter", bool]]: @@ -975,14 +1126,8 @@ class ModuleLevelDocumenter(Documenter): ) -> Tuple[str, List[str]]: if modname is None: if path: - stripped = path.rstrip('.') - modname, qualname = split_full_qualified_name(stripped) - if qualname: - parents = qualname.split(".") - else: - parents = [] - - if modname is None: + modname = path.rstrip('.') + else: # if documenting a toplevel object without explicit module, # it can be contained in another auto directive ... modname = self.env.temp_data.get('autodoc:module') @@ -1015,13 +1160,8 @@ class ClassLevelDocumenter(Documenter): # ... if still None, there's no way to know if mod_cls is None: return None, [] - - try: - modname, qualname = split_full_qualified_name(mod_cls) - parents = qualname.split(".") if qualname else [] - except ImportError: - parents = mod_cls.split(".") - + modname, sep, cls = mod_cls.rpartition('.') + parents = [cls] # if the module name is still missing, get it like above if not modname: modname = self.env.temp_data.get('autodoc:module') @@ -1053,6 +1193,8 @@ class DocstringSignatureMixin: valid_names.extend(cls.__name__ for cls in self.object.__mro__) docstrings = self.get_doc() + if docstrings is None: + return None, None self._new_docstrings = docstrings[:] self._signatures = [] result = None @@ -1103,7 +1245,7 @@ class DocstringSignatureMixin: return result - def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: if encoding is not None: warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." % self.__class__.__name__, @@ -1113,7 +1255,7 @@ class DocstringSignatureMixin: return super().get_doc(None, ignore) # type: ignore def format_signature(self, **kwargs: Any) -> str: - if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore + if self.args is None and self.config.autodoc_docstring_signature: # type: ignore # only act if a signature is not explicitly given already, and if # the feature is enabled result = self._find_signature() @@ -1132,7 +1274,7 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin): feature of stripping any function signature from the docstring. """ def format_signature(self, **kwargs: Any) -> str: - if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore + if self.args is None and self.config.autodoc_docstring_signature: # type: ignore # only act if a signature is not explicitly given already, and if # the feature is enabled result = self._find_signature() @@ -1159,15 +1301,12 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ (inspect.isroutine(member) and isinstance(parent, ModuleDocumenter))) def format_args(self, **kwargs: Any) -> str: - if self.env.config.autodoc_typehints in ('none', 'description'): + if self.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) try: self.env.app.emit('autodoc-before-process-signature', self.object, False) - if inspect.is_singledispatch_function(self.object): - sig = inspect.signature(self.object, follow_wrapped=True) - else: - sig = inspect.signature(self.object) + sig = inspect.signature(self.object, type_aliases=self.config.autodoc_type_aliases) args = stringify_signature(sig, **kwargs) except TypeError as exc: logger.warning(__("Failed to get a function signature for %s: %s"), @@ -1176,7 +1315,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ except ValueError: args = '' - if self.env.config.strip_signature_backslash: + if self.config.strip_signature_backslash: # escape backslashes for reST args = args.replace('\\', '\\\\') return args @@ -1192,8 +1331,16 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ self.add_line(' :async:', sourcename) def format_signature(self, **kwargs: Any) -> str: - sig = super().format_signature(**kwargs) - sigs = [sig] + sigs = [] + if (self.analyzer and + '.'.join(self.objpath) in self.analyzer.overloads and + self.config.autodoc_typehints == 'signature'): + # Use signatures for overloaded functions instead of the implementation function. + overloaded = True + else: + overloaded = False + sig = super().format_signature(**kwargs) + sigs.append(sig) if inspect.is_singledispatch_function(self.object): # append signature of singledispatch'ed functions @@ -1207,27 +1354,52 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ documenter.object = func documenter.objpath = [None] sigs.append(documenter.format_signature()) + if overloaded: + actual = inspect.signature(self.object, + type_aliases=self.config.autodoc_type_aliases) + __globals__ = safe_getattr(self.object, '__globals__', {}) + for overload in self.analyzer.overloads.get('.'.join(self.objpath)): + overload = self.merge_default_value(actual, overload) + overload = evaluate_signature(overload, __globals__, + self.config.autodoc_type_aliases) + + sig = stringify_signature(overload, **kwargs) + sigs.append(sig) return "\n".join(sigs) + def merge_default_value(self, actual: Signature, overload: Signature) -> Signature: + """Merge default values of actual implementation to the overload variants.""" + parameters = list(overload.parameters.values()) + for i, param in enumerate(parameters): + actual_param = actual.parameters.get(param.name) + if actual_param and param.default == '...': + parameters[i] = param.replace(default=actual_param.default) + + return overload.replace(parameters=parameters) + def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: """Annotate type hint to the first argument of function if needed.""" - sig = inspect.signature(func) + try: + sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases) + except TypeError as exc: + logger.warning(__("Failed to get a function signature for %s: %s"), + self.fullname, exc) + return + except ValueError: + return + if len(sig.parameters) == 0: return params = list(sig.parameters.values()) if params[0].annotation is Parameter.empty: params[0] = params[0].replace(annotation=typ) - func.__signature__ = sig.replace(parameters=params) # type: ignore - - -class SingledispatchFunctionDocumenter(FunctionDocumenter): - """ - Used to be a specialized Documenter subclass for singledispatch'ed functions. - - Retained for backwards compatibility, now does the same as the FunctionDocumenter - """ + try: + func.__signature__ = sig.replace(parameters=params) # type: ignore + except TypeError: + # failed to update signature (ex. built-in or extension types) + return class DecoratorDocumenter(FunctionDocumenter): @@ -1255,6 +1427,12 @@ _METACLASS_CALL_BLACKLIST = [ ] +# Types whose __new__ signature is a pass-thru. +_CLASS_NEW_BLACKLIST = [ + 'typing.Generic.__new__', +] + + class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore """ Specialized Documenter subclass for classes. @@ -1265,21 +1443,24 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: 'members': members_option, 'undoc-members': bool_option, 'noindex': bool_option, 'inherited-members': inherited_members_option, 'show-inheritance': bool_option, 'member-order': member_order_option, - 'exclude-members': members_set_option, - 'private-members': bool_option, 'special-members': members_option, + 'exclude-members': exclude_members_option, + 'private-members': members_option, 'special-members': members_option, } # type: Dict[str, Callable] + _signature_class = None # type: Any + _signature_method_name = None # type: str + def __init__(self, *args: Any) -> None: super().__init__(*args) - merge_special_members_option(self.options) + merge_members_option(self.options) @classmethod def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any ) -> bool: return isinstance(member, type) - def import_object(self) -> Any: - ret = super().import_object() + def import_object(self, raiseerror: bool = False) -> bool: + ret = super().import_object(raiseerror) # if the class is documented under another name, document it # as data/attribute if ret: @@ -1289,7 +1470,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: self.doc_as_attr = True return ret - def _get_signature(self) -> Optional[Signature]: + def _get_signature(self) -> Tuple[Optional[Any], Optional[str], Optional[Signature]]: def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: """ Get the `attr` function or method from `obj`, if it is user-defined. """ if inspect.is_builtin_class_method(obj, attr): @@ -1302,7 +1483,12 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: # This sequence is copied from inspect._signature_from_callable. # ValueError means that no signature could be found, so we keep going. - # First, let's see if it has an overloaded __call__ defined + # First, we check the obj has a __signature__ attribute + if (hasattr(self.object, '__signature__') and + isinstance(self.object.__signature__, Signature)): + return None, None, self.object.__signature__ + + # Next, let's see if it has an overloaded __call__ defined # in its metaclass call = get_user_defined_function_or_method(type(self.object), '__call__') @@ -1313,16 +1499,25 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if call is not None: self.env.app.emit('autodoc-before-process-signature', call, True) try: - return inspect.signature(call, bound_method=True) + sig = inspect.signature(call, bound_method=True, + type_aliases=self.config.autodoc_type_aliases) + return type(self.object), '__call__', sig except ValueError: pass # Now we check if the 'obj' class has a '__new__' method new = get_user_defined_function_or_method(self.object, '__new__') + + if new is not None: + if "{0.__module__}.{0.__qualname__}".format(new) in _CLASS_NEW_BLACKLIST: + new = None + if new is not None: self.env.app.emit('autodoc-before-process-signature', new, True) try: - return inspect.signature(new, bound_method=True) + sig = inspect.signature(new, bound_method=True, + type_aliases=self.config.autodoc_type_aliases) + return self.object, '__new__', sig except ValueError: pass @@ -1331,7 +1526,9 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if init is not None: self.env.app.emit('autodoc-before-process-signature', init, True) try: - return inspect.signature(init, bound_method=True) + sig = inspect.signature(init, bound_method=True, + type_aliases=self.config.autodoc_type_aliases) + return self.object, '__init__', sig except ValueError: pass @@ -1341,20 +1538,22 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: # the signature from, so just pass the object itself to our hook. self.env.app.emit('autodoc-before-process-signature', self.object, False) try: - return inspect.signature(self.object, bound_method=False) + sig = inspect.signature(self.object, bound_method=False, + type_aliases=self.config.autodoc_type_aliases) + return None, None, sig except ValueError: pass # Still no signature: happens e.g. for old-style classes # with __init__ in C and no `__text_signature__`. - return None + return None, None, None def format_args(self, **kwargs: Any) -> str: - if self.env.config.autodoc_typehints in ('none', 'description'): + if self.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) try: - sig = self._get_signature() + self._signature_class, self._signature_method_name, sig = self._get_signature() except TypeError as exc: # __signature__ attribute contained junk logger.warning(__("Failed to get a constructor signature for %s: %s"), @@ -1370,7 +1569,44 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if self.doc_as_attr: return '' - return super().format_signature(**kwargs) + sig = super().format_signature() + sigs = [] + + overloads = self.get_overloaded_signatures() + if overloads and self.config.autodoc_typehints == 'signature': + # Use signatures for overloaded methods instead of the implementation method. + method = safe_getattr(self._signature_class, self._signature_method_name, None) + __globals__ = safe_getattr(method, '__globals__', {}) + for overload in overloads: + overload = evaluate_signature(overload, __globals__, + self.config.autodoc_type_aliases) + + parameters = list(overload.parameters.values()) + overload = overload.replace(parameters=parameters[1:], + return_annotation=Parameter.empty) + sig = stringify_signature(overload, **kwargs) + sigs.append(sig) + else: + sigs.append(sig) + + return "\n".join(sigs) + + def get_overloaded_signatures(self) -> List[Signature]: + if self._signature_class and self._signature_method_name: + for cls in self._signature_class.__mro__: + try: + analyzer = ModuleAnalyzer.for_module(cls.__module__) + analyzer.analyze() + qualname = '.'.join([cls.__qualname__, self._signature_method_name]) + if qualname in analyzer.overloads: + return analyzer.overloads.get(qualname) + elif qualname in analyzer.tagorder: + # the constructor is defined in the class, but not overrided. + return [] + except PycodeError: + pass + + return [] def add_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() @@ -1386,24 +1622,50 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if not self.doc_as_attr and self.options.show_inheritance: sourcename = self.get_sourcename() self.add_line('', sourcename) - if hasattr(self.object, '__bases__') and len(self.object.__bases__): - bases = [':class:`%s`' % b.__name__ - if b.__module__ in ('__builtin__', 'builtins') - else ':class:`%s.%s`' % (b.__module__, b.__qualname__) - for b in self.object.__bases__] - self.add_line(' ' + _('Bases: %s') % ', '.join(bases), - sourcename) - def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: + if hasattr(self.object, '__orig_bases__') and len(self.object.__orig_bases__): + # A subclass of generic types + # refs: PEP-560 <https://www.python.org/dev/peps/pep-0560/> + bases = [restify(cls) for cls in self.object.__orig_bases__] + self.add_line(' ' + _('Bases: %s') % ', '.join(bases), sourcename) + elif hasattr(self.object, '__bases__') and len(self.object.__bases__): + # A normal class + bases = [restify(cls) for cls in self.object.__bases__] + self.add_line(' ' + _('Bases: %s') % ', '.join(bases), sourcename) + + def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]: + members = get_class_members(self.object, self.objpath, self.get_attr) + if not want_all: + if not self.options.members: + return False, [] # type: ignore + # specific members given + selected = [] + for name in self.options.members: # type: str + if name in members: + selected.append(members[name]) + else: + logger.warning(__('missing attribute %s in object %s') % + (name, self.fullname), type='autodoc') + return False, selected + elif self.options.inherited_members: + return False, list(members.values()) + else: + return False, [m for m in members.values() if m.class_ == self.object] + + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: if encoding is not None: warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." % self.__class__.__name__, RemovedInSphinx40Warning, stacklevel=2) + if self.doc_as_attr: + # Don't show the docstring of the class when it is an alias. + return None + lines = getattr(self, '_new_docstrings', None) if lines is not None: return lines - content = self.env.config.autoclass_content + content = self.config.autoclass_content docstrings = [] attrdocstring = self.get_attr(self.object, '__doc__', None) @@ -1415,7 +1677,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if content in ('both', 'init'): __init__ = self.get_attr(self.object, '__init__', None) initdocstring = getdoc(__init__, self.get_attr, - self.env.config.autodoc_inherit_docstrings, + self.config.autodoc_inherit_docstrings, self.parent, self.object_name) # for new-style classes, no __init__ means default __init__ if (initdocstring is not None and @@ -1426,7 +1688,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: # try __new__ __new__ = self.get_attr(self.object, '__new__', None) initdocstring = getdoc(__new__, self.get_attr, - self.env.config.autodoc_inherit_docstrings, + self.config.autodoc_inherit_docstrings, self.parent, self.object_name) # for new-style classes, no __new__ means default __new__ if (initdocstring is not None and @@ -1442,27 +1704,22 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: tab_width = self.directive.state.document.settings.tab_width return [prepare_docstring(docstring, ignore, tab_width) for docstring in docstrings] - def add_content(self, more_content: Any, no_docstring: bool = False) -> None: + def add_content(self, more_content: Optional[StringList], no_docstring: bool = False + ) -> None: if self.doc_as_attr: - classname = safe_getattr(self.object, '__qualname__', None) - if not classname: - classname = safe_getattr(self.object, '__name__', None) - if classname: - module = safe_getattr(self.object, '__module__', None) - parentmodule = safe_getattr(self.parent, '__module__', None) - if module and module != parentmodule: - classname = str(module) + '.' + str(classname) - content = StringList([_('alias of :class:`%s`') % classname], source='') - super().add_content(content, no_docstring=True) - else: - super().add_content(more_content) + try: + more_content = StringList([_('alias of %s') % restify(self.object)], source='') + except AttributeError: + pass # Invalid class object is passed. + + super().add_content(more_content) def document_members(self, all_members: bool = False) -> None: if self.doc_as_attr: return super().document_members(all_members) - def generate(self, more_content: Any = None, real_modname: str = None, + def generate(self, more_content: Optional[StringList] = None, real_modname: str = None, check_module: bool = False, all_members: bool = False) -> None: # Do not pass real_modname and use the name from the __module__ # attribute of the class. @@ -1490,7 +1747,149 @@ class ExceptionDocumenter(ClassDocumenter): return isinstance(member, type) and issubclass(member, BaseException) -class DataDocumenter(ModuleLevelDocumenter): +class DataDocumenterMixinBase: + # define types of instance variables + config = None # type: Config + env = None # type: BuildEnvironment + modname = None # type: str + parent = None # type: Any + object = None # type: Any + objpath = None # type: List[str] + + def should_suppress_directive_header(self) -> bool: + """Check directive header should be suppressed.""" + return False + + def should_suppress_value_header(self) -> bool: + """Check :value: header should be suppressed.""" + return False + + def update_content(self, more_content: StringList) -> None: + """Update docstring for the NewType object.""" + pass + + +class GenericAliasMixin(DataDocumenterMixinBase): + """ + Mixin for DataDocumenter and AttributeDocumenter to provide the feature for + supporting GenericAliases. + """ + + def should_suppress_directive_header(self) -> bool: + return (inspect.isgenericalias(self.object) or + super().should_suppress_directive_header()) + + def update_content(self, more_content: StringList) -> None: + if inspect.isgenericalias(self.object): + alias = stringify_typehint(self.object) + more_content.append(_('alias of %s') % alias, '') + more_content.append('', '') + + super().update_content(more_content) + + +class NewTypeMixin(DataDocumenterMixinBase): + """ + Mixin for DataDocumenter and AttributeDocumenter to provide the feature for + supporting NewTypes. + """ + + def should_suppress_directive_header(self) -> bool: + return (inspect.isNewType(self.object) or + super().should_suppress_directive_header()) + + def update_content(self, more_content: StringList) -> None: + if inspect.isNewType(self.object): + supertype = restify(self.object.__supertype__) + more_content.append(_('alias of %s') % supertype, '') + more_content.append('', '') + + super().update_content(more_content) + + +class TypeVarMixin(DataDocumenterMixinBase): + """ + Mixin for DataDocumenter and AttributeDocumenter to provide the feature for + supporting TypeVars. + """ + + def should_suppress_directive_header(self) -> bool: + return (isinstance(self.object, TypeVar) or + super().should_suppress_directive_header()) + + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: + if ignore is not None: + warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated." + % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + + if isinstance(self.object, TypeVar): + if self.object.__doc__ != TypeVar.__doc__: + return super().get_doc() # type: ignore + else: + return [] + else: + return super().get_doc() # type: ignore + + def update_content(self, more_content: StringList) -> None: + if isinstance(self.object, TypeVar): + attrs = [repr(self.object.__name__)] + for constraint in self.object.__constraints__: + attrs.append(stringify_typehint(constraint)) + if self.object.__covariant__: + attrs.append("covariant=True") + if self.object.__contravariant__: + attrs.append("contravariant=True") + + more_content.append(_('alias of TypeVar(%s)') % ", ".join(attrs), '') + more_content.append('', '') + + super().update_content(more_content) + + +class UninitializedGlobalVariableMixin(DataDocumenterMixinBase): + """ + Mixin for DataDocumenter to provide the feature for supporting uninitialized + (type annotation only) global variables. + """ + + def import_object(self, raiseerror: bool = False) -> bool: + try: + return super().import_object(raiseerror=True) # type: ignore + except ImportError as exc: + # annotation only instance variable (PEP-526) + try: + with mock(self.config.autodoc_mock_imports): + parent = import_module(self.modname, self.config.autodoc_warningiserror) + annotations = get_type_hints(parent, None, + self.config.autodoc_type_aliases) + if self.objpath[-1] in annotations: + self.object = UNINITIALIZED_ATTR + self.parent = parent + return True + except ImportError: + pass + + if raiseerror: + raise + else: + logger.warning(exc.args[0], type='autodoc', subtype='import_object') + self.env.note_reread() + return False + + def should_suppress_value_header(self) -> bool: + return (self.object is UNINITIALIZED_ATTR or + super().should_suppress_value_header()) + + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: + if self.object is UNINITIALIZED_ATTR: + return [] + else: + return super().get_doc(encoding, ignore) # type: ignore + + +class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin, + UninitializedGlobalVariableMixin, ModuleLevelDocumenter): """ Specialized Documenter subclass for data items. """ @@ -1499,40 +1898,68 @@ class DataDocumenter(ModuleLevelDocumenter): priority = -10 option_spec = dict(ModuleLevelDocumenter.option_spec) option_spec["annotation"] = annotation_option + option_spec["no-value"] = bool_option @classmethod def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any ) -> bool: return isinstance(parent, ModuleDocumenter) and isattr + def update_annotations(self, parent: Any) -> None: + """Update __annotations__ to support type_comment and so on.""" + try: + annotations = dict(inspect.getannotations(parent)) + parent.__annotations__ = annotations + + analyzer = ModuleAnalyzer.for_module(self.modname) + analyzer.analyze() + for (classname, attrname), annotation in analyzer.annotations.items(): + if classname == '' and attrname not in annotations: + annotations[attrname] = annotation + except AttributeError: + pass + + def import_object(self, raiseerror: bool = False) -> bool: + ret = super().import_object(raiseerror) + if self.parent: + self.update_annotations(self.parent) + + return ret + + def should_suppress_value_header(self) -> bool: + if super().should_suppress_value_header(): + return True + else: + doc = self.get_doc() + metadata = extract_metadata('\n'.join(sum(doc, []))) + if 'hide-value' in metadata: + return True + + return False + def add_directive_header(self, sig: str) -> None: super().add_directive_header(sig) sourcename = self.get_sourcename() - if not self.options.annotation: + if self.options.annotation is SUPPRESS or self.should_suppress_directive_header(): + pass + elif self.options.annotation: + self.add_line(' :annotation: %s' % self.options.annotation, + sourcename) + else: # obtain annotation for this data - annotations = getattr(self.parent, '__annotations__', {}) - if annotations and self.objpath[-1] in annotations: + annotations = get_type_hints(self.parent, None, self.config.autodoc_type_aliases) + if self.objpath[-1] in annotations: objrepr = stringify_typehint(annotations.get(self.objpath[-1])) self.add_line(' :type: ' + objrepr, sourcename) - else: - key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) - if self.analyzer and key in self.analyzer.annotations: - self.add_line(' :type: ' + self.analyzer.annotations[key], - sourcename) try: - if self.object is UNINITIALIZED_ATTR: + if self.options.no_value or self.should_suppress_value_header(): pass else: objrepr = object_description(self.object) self.add_line(' :value: ' + objrepr, sourcename) except ValueError: pass - elif self.options.annotation is SUPPRESS: - pass - else: - self.add_line(' :annotation: %s' % self.options.annotation, - sourcename) def document_members(self, all_members: bool = False) -> None: pass @@ -1541,67 +1968,55 @@ class DataDocumenter(ModuleLevelDocumenter): return self.get_attr(self.parent or self.object, '__module__', None) \ or self.modname + def get_module_comment(self, attrname: str) -> Optional[List[str]]: + try: + analyzer = ModuleAnalyzer.for_module(self.modname) + analyzer.analyze() + key = ('', attrname) + if key in analyzer.attr_docs: + return list(analyzer.attr_docs[key]) + except PycodeError: + pass -class DataDeclarationDocumenter(DataDocumenter): - """ - Specialized Documenter subclass for data that cannot be imported - because they are declared without initial value (refs: PEP-526). - """ - objtype = 'datadecl' - directivetype = 'data' - member_order = 60 + return None - # must be higher than AttributeDocumenter - priority = 11 + def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: + # Check the variable has a docstring-comment + comment = self.get_module_comment(self.objpath[-1]) + if comment: + return [comment] + else: + return super().get_doc(encoding, ignore) - @classmethod - def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any - ) -> bool: - """This documents only INSTANCEATTR members.""" - return (isinstance(parent, ModuleDocumenter) and - isattr and - member is INSTANCEATTR) - - def import_object(self) -> bool: - """Never import anything.""" - # disguise as a data - self.objtype = 'data' - self.object = UNINITIALIZED_ATTR - try: - # import module to obtain type annotation - self.parent = importlib.import_module(self.modname) - except ImportError: - pass + def add_content(self, more_content: Optional[StringList], no_docstring: bool = False + ) -> None: + # Disable analyzing variable comment on Documenter.add_content() to control it on + # DataDocumenter.add_content() + self.analyzer = None - return True + if not more_content: + more_content = StringList() - def add_content(self, more_content: Any, no_docstring: bool = False) -> None: - """Never try to get a docstring from the object.""" - super().add_content(more_content, no_docstring=True) + self.update_content(more_content) + super().add_content(more_content, no_docstring=no_docstring) -class GenericAliasDocumenter(DataDocumenter): +class NewTypeDataDocumenter(DataDocumenter): """ - Specialized Documenter subclass for GenericAliases. + Specialized Documenter subclass for NewTypes. + + Note: This must be invoked before FunctionDocumenter because NewType is a kind of + function object. """ - objtype = 'genericalias' + objtype = 'newtypedata' directivetype = 'data' - priority = DataDocumenter.priority + 1 + priority = FunctionDocumenter.priority + 1 @classmethod def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any ) -> bool: - return inspect.isgenericalias(member) - - def add_directive_header(self, sig: str) -> None: - self.options.annotation = SUPPRESS # type: ignore - super().add_directive_header(sig) - - def add_content(self, more_content: Any, no_docstring: bool = False) -> None: - name = stringify_typehint(self.object) - content = StringList([_('alias of %s') % name], source='') - super().add_content(content) + return inspect.isNewType(member) and isattr class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: ignore @@ -1619,8 +2034,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: return inspect.isroutine(member) and \ not isinstance(parent, ModuleDocumenter) - def import_object(self) -> Any: - ret = super().import_object() + def import_object(self, raiseerror: bool = False) -> bool: + ret = super().import_object(raiseerror) if not ret: return ret @@ -1637,7 +2052,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: return ret def format_args(self, **kwargs: Any) -> str: - if self.env.config.autodoc_typehints in ('none', 'description'): + if self.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) try: @@ -1650,16 +2065,12 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: else: if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name): self.env.app.emit('autodoc-before-process-signature', self.object, False) - sig = inspect.signature(self.object, bound_method=False) + sig = inspect.signature(self.object, bound_method=False, + type_aliases=self.config.autodoc_type_aliases) else: self.env.app.emit('autodoc-before-process-signature', self.object, True) - - meth = self.parent.__dict__.get(self.objpath[-1], None) - if meth and inspect.is_singledispatch_method(meth): - sig = inspect.signature(self.object, bound_method=True, - follow_wrapped=True) - else: - sig = inspect.signature(self.object, bound_method=True) + sig = inspect.signature(self.object, bound_method=True, + type_aliases=self.config.autodoc_type_aliases) args = stringify_signature(sig, **kwargs) except TypeError as exc: logger.warning(__("Failed to get a method signature for %s: %s"), @@ -1668,7 +2079,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: except ValueError: args = '' - if self.env.config.strip_signature_backslash: + if self.config.strip_signature_backslash: # escape backslashes for reST args = args.replace('\\', '\\\\') return args @@ -1693,8 +2104,16 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: pass def format_signature(self, **kwargs: Any) -> str: - sig = super().format_signature(**kwargs) - sigs = [sig] + sigs = [] + if (self.analyzer and + '.'.join(self.objpath) in self.analyzer.overloads and + self.config.autodoc_typehints == 'signature'): + # Use signatures for overloaded methods instead of the implementation method. + overloaded = True + else: + overloaded = False + sig = super().format_signature(**kwargs) + sigs.append(sig) meth = self.parent.__dict__.get(self.objpath[-1]) if inspect.is_singledispatch_method(meth): @@ -1710,30 +2129,252 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: documenter.object = func documenter.objpath = [None] sigs.append(documenter.format_signature()) + if overloaded: + if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name): + actual = inspect.signature(self.object, bound_method=False, + type_aliases=self.config.autodoc_type_aliases) + else: + actual = inspect.signature(self.object, bound_method=True, + type_aliases=self.config.autodoc_type_aliases) + + __globals__ = safe_getattr(self.object, '__globals__', {}) + for overload in self.analyzer.overloads.get('.'.join(self.objpath)): + overload = self.merge_default_value(actual, overload) + overload = evaluate_signature(overload, __globals__, + self.config.autodoc_type_aliases) + + if not inspect.isstaticmethod(self.object, cls=self.parent, + name=self.object_name): + parameters = list(overload.parameters.values()) + overload = overload.replace(parameters=parameters[1:]) + sig = stringify_signature(overload, **kwargs) + sigs.append(sig) return "\n".join(sigs) + def merge_default_value(self, actual: Signature, overload: Signature) -> Signature: + """Merge default values of actual implementation to the overload variants.""" + parameters = list(overload.parameters.values()) + for i, param in enumerate(parameters): + actual_param = actual.parameters.get(param.name) + if actual_param and param.default == '...': + parameters[i] = param.replace(default=actual_param.default) + + return overload.replace(parameters=parameters) + def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: """Annotate type hint to the first argument of function if needed.""" - sig = inspect.signature(func) + try: + sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases) + except TypeError as exc: + logger.warning(__("Failed to get a method signature for %s: %s"), + self.fullname, exc) + return + except ValueError: + return if len(sig.parameters) == 1: return params = list(sig.parameters.values()) if params[1].annotation is Parameter.empty: params[1] = params[1].replace(annotation=typ) - func.__signature__ = sig.replace(parameters=params) # type: ignore + try: + func.__signature__ = sig.replace(parameters=params) # type: ignore + except TypeError: + # failed to update signature (ex. built-in or extension types) + return + + +class NonDataDescriptorMixin(DataDocumenterMixinBase): + """ + Mixin for AttributeDocumenter to provide the feature for supporting non + data-descriptors. + + .. note:: This mix-in must be inherited after other mix-ins. Otherwise, docstring + and :value: header will be suppressed unexpectedly. + """ + + def import_object(self, raiseerror: bool = False) -> bool: + ret = super().import_object(raiseerror) # type: ignore + if ret and not inspect.isattributedescriptor(self.object): + self.non_data_descriptor = True + else: + self.non_data_descriptor = False + + return ret + + def should_suppress_value_header(self) -> bool: + return (not getattr(self, 'non_data_descriptor', False) or + super().should_suppress_directive_header()) + + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: + if getattr(self, 'non_data_descriptor', False): + # the docstring of non datadescriptor is very probably the wrong thing + # to display + return None + else: + return super().get_doc(encoding, ignore) # type: ignore + + +class SlotsMixin(DataDocumenterMixinBase): + """ + Mixin for AttributeDocumenter to provide the feature for supporting __slots__. + """ + + def isslotsattribute(self) -> bool: + """Check the subject is an attribute in __slots__.""" + try: + __slots__ = inspect.getslots(self.parent) + if __slots__ and self.objpath[-1] in __slots__: + return True + else: + return False + except (AttributeError, ValueError, TypeError): + return False + + def import_object(self, raiseerror: bool = False) -> bool: + ret = super().import_object(raiseerror) # type: ignore + if self.isslotsattribute(): + self.object = SLOTSATTR + + return ret + + def should_suppress_directive_header(self) -> bool: + if self.object is SLOTSATTR: + self._datadescriptor = True + return True + else: + return super().should_suppress_directive_header() + + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: + if self.object is SLOTSATTR: + try: + __slots__ = inspect.getslots(self.parent) + if __slots__ and __slots__.get(self.objpath[-1]): + docstring = prepare_docstring(__slots__[self.objpath[-1]]) + return [docstring] + else: + return [] + except (AttributeError, ValueError) as exc: + logger.warning(__('Invalid __slots__ found on %s. Ignored.'), + (self.parent.__qualname__, exc), type='autodoc') + return [] + else: + return super().get_doc(encoding, ignore) # type: ignore + + +class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase): + """ + Mixin for AttributeDocumenter to provide the feature for supporting runtime + instance attributes (that are defined in __init__() methods with doc-comments). + + Example: + + class Foo: + def __init__(self): + self.attr = None #: This is a target of this mix-in. + """ + + RUNTIME_INSTANCE_ATTRIBUTE = object() + + def is_runtime_instance_attribute(self, parent: Any) -> bool: + """Check the subject is an attribute defined in __init__().""" + # An instance variable defined in __init__(). + if self.get_attribute_comment(parent, self.objpath[-1]): # type: ignore + return True + else: + return False + + def import_object(self, raiseerror: bool = False) -> bool: + """Check the existence of runtime instance attribute when failed to import the + attribute.""" + try: + return super().import_object(raiseerror=True) # type: ignore + except ImportError as exc: + try: + with mock(self.config.autodoc_mock_imports): + ret = import_object(self.modname, self.objpath[:-1], 'class', + attrgetter=self.get_attr, # type: ignore + warningiserror=self.config.autodoc_warningiserror) + parent = ret[3] + if self.is_runtime_instance_attribute(parent): + self.object = self.RUNTIME_INSTANCE_ATTRIBUTE + self.parent = parent + return True + except ImportError: + pass + + if raiseerror: + raise + else: + logger.warning(exc.args[0], type='autodoc', subtype='import_object') + self.env.note_reread() + return False + def should_suppress_value_header(self) -> bool: + return (self.object is self.RUNTIME_INSTANCE_ATTRIBUTE or + super().should_suppress_value_header()) -class SingledispatchMethodDocumenter(MethodDocumenter): + +class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase): """ - Used to be a specialized Documenter subclass for singledispatch'ed methods. + Mixin for AttributeDocumenter to provide the feature for supporting uninitialized + instance attributes (PEP-526 styled, annotation only attributes). + + Example: - Retained for backwards compatibility, now does the same as the MethodDocumenter + class Foo: + attr: int #: This is a target of this mix-in. """ + def is_uninitialized_instance_attribute(self, parent: Any) -> bool: + """Check the subject is an annotation only attribute.""" + annotations = get_type_hints(parent, None, self.config.autodoc_type_aliases) + if self.objpath[-1] in annotations: + return True + else: + return False + + def import_object(self, raiseerror: bool = False) -> bool: + """Check the exisitence of uninitialized instance attribute when failed to import + the attribute.""" + try: + return super().import_object(raiseerror=True) # type: ignore + except ImportError as exc: + try: + ret = import_object(self.modname, self.objpath[:-1], 'class', + attrgetter=self.get_attr, # type: ignore + warningiserror=self.config.autodoc_warningiserror) + parent = ret[3] + if self.is_uninitialized_instance_attribute(parent): + self.object = UNINITIALIZED_ATTR + self.parent = parent + return True + except ImportError: + pass + + if raiseerror: + raise + else: + logger.warning(exc.args[0], type='autodoc', subtype='import_object') + self.env.note_reread() + return False + + def should_suppress_value_header(self) -> bool: + return (self.object is UNINITIALIZED_ATTR or + super().should_suppress_value_header()) + + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: + if self.object is UNINITIALIZED_ATTR: + return None + else: + return super().get_doc(encoding, ignore) # type: ignore + -class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore +class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type: ignore + TypeVarMixin, RuntimeInstanceAttributeMixin, + UninitializedInstanceAttributeMixin, NonDataDescriptorMixin, + DocstringStripSignatureMixin, ClassLevelDocumenter): """ Specialized Documenter subclass for attributes. """ @@ -1741,6 +2382,7 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): member_order = 60 option_spec = dict(ModuleLevelDocumenter.option_spec) option_spec["annotation"] = annotation_option + option_spec["no-value"] = bool_option # must be higher than the MethodDocumenter, else it will recognize # some non-data descriptors as methods @@ -1765,56 +2407,144 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): def document_members(self, all_members: bool = False) -> None: pass - def import_object(self) -> Any: - ret = super().import_object() + def isinstanceattribute(self) -> bool: + """Check the subject is an instance attribute.""" + warnings.warn('AttributeDocumenter.isinstanceattribute() is deprecated.', + RemovedInSphinx50Warning) + # uninitialized instance variable (PEP-526) + with mock(self.config.autodoc_mock_imports): + try: + ret = import_object(self.modname, self.objpath[:-1], 'class', + attrgetter=self.get_attr, + warningiserror=self.config.autodoc_warningiserror) + self.parent = ret[3] + annotations = get_type_hints(self.parent, None, + self.config.autodoc_type_aliases) + if self.objpath[-1] in annotations: + self.object = UNINITIALIZED_ATTR + return True + except ImportError: + pass + + return False + + def update_annotations(self, parent: Any) -> None: + """Update __annotations__ to support type_comment and so on.""" + try: + annotations = dict(inspect.getannotations(parent)) + parent.__annotations__ = annotations + + for cls in inspect.getmro(parent): + try: + module = safe_getattr(cls, '__module__') + qualname = safe_getattr(cls, '__qualname__') + + analyzer = ModuleAnalyzer.for_module(module) + analyzer.analyze() + for (classname, attrname), annotation in analyzer.annotations.items(): + if classname == qualname and attrname not in annotations: + annotations[attrname] = annotation + except (AttributeError, PycodeError): + pass + except AttributeError: + pass + except TypeError: + # Failed to set __annotations__ (built-in, extensions, etc.) + pass + + def import_object(self, raiseerror: bool = False) -> bool: + ret = super().import_object(raiseerror) if inspect.isenumattribute(self.object): self.object = self.object.value - if inspect.isattributedescriptor(self.object): - self._datadescriptor = True - else: - # if it's not a data descriptor - self._datadescriptor = False + if self.parent: + self.update_annotations(self.parent) + return ret def get_real_modname(self) -> str: return self.get_attr(self.parent or self.object, '__module__', None) \ or self.modname + def should_suppress_value_header(self) -> bool: + if super().should_suppress_value_header(): + return True + else: + doc = self.get_doc() + if doc: + metadata = extract_metadata('\n'.join(sum(doc, []))) + if 'hide-value' in metadata: + return True + + return False + def add_directive_header(self, sig: str) -> None: super().add_directive_header(sig) sourcename = self.get_sourcename() - if not self.options.annotation: + if self.options.annotation is SUPPRESS or self.should_suppress_directive_header(): + pass + elif self.options.annotation: + self.add_line(' :annotation: %s' % self.options.annotation, sourcename) + else: # obtain type annotation for this attribute - annotations = getattr(self.parent, '__annotations__', {}) - if annotations and self.objpath[-1] in annotations: + annotations = get_type_hints(self.parent, None, self.config.autodoc_type_aliases) + if self.objpath[-1] in annotations: objrepr = stringify_typehint(annotations.get(self.objpath[-1])) self.add_line(' :type: ' + objrepr, sourcename) - else: - key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) - if self.analyzer and key in self.analyzer.annotations: - self.add_line(' :type: ' + self.analyzer.annotations[key], - sourcename) - # data descriptors do not have useful values - if not self._datadescriptor: + try: + if self.options.no_value or self.should_suppress_value_header(): + pass + else: + objrepr = object_description(self.object) + self.add_line(' :value: ' + objrepr, sourcename) + except ValueError: + pass + + def get_attribute_comment(self, parent: Any, attrname: str) -> Optional[List[str]]: + try: + for cls in inspect.getmro(parent): try: - if self.object is INSTANCEATTR: - pass - else: - objrepr = object_description(self.object) - self.add_line(' :value: ' + objrepr, sourcename) - except ValueError: + module = safe_getattr(cls, '__module__') + qualname = safe_getattr(cls, '__qualname__') + + analyzer = ModuleAnalyzer.for_module(module) + analyzer.analyze() + if qualname and self.objpath: + key = (qualname, attrname) + if key in analyzer.attr_docs: + return list(analyzer.attr_docs[key]) + except (AttributeError, PycodeError): pass - elif self.options.annotation is SUPPRESS: + except (AttributeError, PycodeError): pass - else: - self.add_line(' :annotation: %s' % self.options.annotation, sourcename) - def add_content(self, more_content: Any, no_docstring: bool = False) -> None: - if not self._datadescriptor: - # if it's not a data descriptor, its docstring is very probably the - # wrong thing to display - no_docstring = True + return None + + def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]: + # Check the attribute has a docstring-comment + comment = self.get_attribute_comment(self.parent, self.objpath[-1]) + if comment: + return [comment] + + try: + # Disable `autodoc_inherit_docstring` temporarily to avoid to obtain + # a docstring from the value which descriptor returns unexpectedly. + # ref: https://github.com/sphinx-doc/sphinx/issues/7805 + orig = self.config.autodoc_inherit_docstrings + self.config.autodoc_inherit_docstrings = False # type: ignore + return super().get_doc(encoding, ignore) + finally: + self.config.autodoc_inherit_docstrings = orig # type: ignore + + def add_content(self, more_content: Optional[StringList], no_docstring: bool = False + ) -> None: + # Disable analyzing attribute comment on Documenter.add_content() to control it on + # AttributeDocumenter.add_content() + self.analyzer = None + + if more_content is None: + more_content = StringList() + self.update_content(more_content) super().add_content(more_content, no_docstring) @@ -1849,88 +2579,22 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # self.add_line(' :property:', sourcename) -class InstanceAttributeDocumenter(AttributeDocumenter): - """ - Specialized Documenter subclass for attributes that cannot be imported - because they are instance attributes (e.g. assigned in __init__). +class NewTypeAttributeDocumenter(AttributeDocumenter): """ - objtype = 'instanceattribute' - directivetype = 'attribute' - member_order = 60 - - # must be higher than AttributeDocumenter - priority = 11 - - @classmethod - def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any - ) -> bool: - """This documents only INSTANCEATTR members.""" - return (not isinstance(parent, ModuleDocumenter) and - isattr and - member is INSTANCEATTR) - - def import_object(self) -> bool: - """Never import anything.""" - # disguise as an attribute - self.objtype = 'attribute' - self.object = INSTANCEATTR - self._datadescriptor = False - return True - - def add_content(self, more_content: Any, no_docstring: bool = False) -> None: - """Never try to get a docstring from the object.""" - super().add_content(more_content, no_docstring=True) + Specialized Documenter subclass for NewTypes. - -class SlotsAttributeDocumenter(AttributeDocumenter): - """ - Specialized Documenter subclass for attributes that cannot be imported - because they are attributes in __slots__. + Note: This must be invoked before MethodDocumenter because NewType is a kind of + function object. """ - objtype = 'slotsattribute' - directivetype = 'attribute' - member_order = 60 - # must be higher than AttributeDocumenter - priority = 11 + objtype = 'newvarattribute' + directivetype = 'attribute' + priority = MethodDocumenter.priority + 1 @classmethod def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any ) -> bool: - """This documents only SLOTSATTR members.""" - return member is SLOTSATTR - - def import_object(self) -> Any: - """Never import anything.""" - # disguise as an attribute - self.objtype = 'attribute' - self._datadescriptor = True - - with mock(self.env.config.autodoc_mock_imports): - try: - ret = import_object(self.modname, self.objpath[:-1], 'class', - attrgetter=self.get_attr, - warningiserror=self.env.config.autodoc_warningiserror) - self.module, _, _, self.parent = ret - return True - except ImportError as exc: - logger.warning(exc.args[0], type='autodoc', subtype='import_object') - self.env.note_reread() - return False - - def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: - """Decode and return lines of the docstring(s) for the object.""" - if ignore is not None: - warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated." - % self.__class__.__name__, - RemovedInSphinx50Warning, stacklevel=2) - name = self.objpath[-1] - __slots__ = safe_getattr(self.parent, '__slots__', []) - if isinstance(__slots__, dict) and isinstance(__slots__.get(name), str): - docstring = prepare_docstring(__slots__[name]) - return [docstring] - else: - return [] + return not isinstance(parent, ModuleDocumenter) and inspect.isNewType(member) def get_documenters(app: Sphinx) -> Dict[str, "Type[Documenter]"]: @@ -1956,20 +2620,28 @@ def migrate_autodoc_member_order(app: Sphinx, config: Config) -> None: config.autodoc_member_order = 'alphabetical' # type: ignore +# for compatibility +from sphinx.ext.autodoc.deprecated import DataDeclarationDocumenter # NOQA +from sphinx.ext.autodoc.deprecated import GenericAliasDocumenter # NOQA +from sphinx.ext.autodoc.deprecated import InstanceAttributeDocumenter # NOQA +from sphinx.ext.autodoc.deprecated import SingledispatchFunctionDocumenter # NOQA +from sphinx.ext.autodoc.deprecated import SingledispatchMethodDocumenter # NOQA +from sphinx.ext.autodoc.deprecated import SlotsAttributeDocumenter # NOQA +from sphinx.ext.autodoc.deprecated import TypeVarDocumenter # NOQA + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_autodocumenter(ModuleDocumenter) app.add_autodocumenter(ClassDocumenter) app.add_autodocumenter(ExceptionDocumenter) app.add_autodocumenter(DataDocumenter) - app.add_autodocumenter(DataDeclarationDocumenter) - app.add_autodocumenter(GenericAliasDocumenter) + app.add_autodocumenter(NewTypeDataDocumenter) app.add_autodocumenter(FunctionDocumenter) app.add_autodocumenter(DecoratorDocumenter) app.add_autodocumenter(MethodDocumenter) app.add_autodocumenter(AttributeDocumenter) app.add_autodocumenter(PropertyDocumenter) - app.add_autodocumenter(InstanceAttributeDocumenter) - app.add_autodocumenter(SlotsAttributeDocumenter) + app.add_autodocumenter(NewTypeAttributeDocumenter) app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init')) app.add_config_value('autodoc_member_order', 'alphabetical', True, @@ -1979,6 +2651,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('autodoc_mock_imports', [], True) app.add_config_value('autodoc_typehints', "signature", True, ENUM("signature", "description", "none")) + app.add_config_value('autodoc_type_aliases', {}, True) app.add_config_value('autodoc_warningiserror', True, True) app.add_config_value('autodoc_inherit_docstrings', True, True) app.add_event('autodoc-before-process-signature') diff --git a/sphinx/ext/autodoc/deprecated.py b/sphinx/ext/autodoc/deprecated.py new file mode 100644 index 000000000..80a94f0ea --- /dev/null +++ b/sphinx/ext/autodoc/deprecated.py @@ -0,0 +1,126 @@ +""" + sphinx.ext.autodoc.deprecated + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The deprecated Documenters for autodoc. + + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import warnings +from typing import Any + +from sphinx.deprecation import RemovedInSphinx50Warning +from sphinx.ext.autodoc import (AttributeDocumenter, DataDocumenter, FunctionDocumenter, + MethodDocumenter) + + +class SingledispatchFunctionDocumenter(FunctionDocumenter): + """ + Used to be a specialized Documenter subclass for singledispatch'ed functions. + + Retained for backwards compatibility, now does the same as the FunctionDocumenter + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + warnings.warn("%s is deprecated." % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + super().__init__(*args, **kwargs) + + +class DataDeclarationDocumenter(DataDocumenter): + """ + Specialized Documenter subclass for data that cannot be imported + because they are declared without initial value (refs: PEP-526). + """ + objtype = 'datadecl' + directivetype = 'data' + member_order = 60 + + # must be higher than AttributeDocumenter + priority = 11 + + def __init__(self, *args: Any, **kwargs: Any) -> None: + warnings.warn("%s is deprecated." % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + super().__init__(*args, **kwargs) + + +class TypeVarDocumenter(DataDocumenter): + """ + Specialized Documenter subclass for TypeVars. + """ + + objtype = 'typevar' + directivetype = 'data' + priority = DataDocumenter.priority + 1 # type: ignore + + def __init__(self, *args: Any, **kwargs: Any) -> None: + warnings.warn("%s is deprecated." % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + super().__init__(*args, **kwargs) + + +class SingledispatchMethodDocumenter(MethodDocumenter): + """ + Used to be a specialized Documenter subclass for singledispatch'ed methods. + + Retained for backwards compatibility, now does the same as the MethodDocumenter + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + warnings.warn("%s is deprecated." % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + super().__init__(*args, **kwargs) + + +class InstanceAttributeDocumenter(AttributeDocumenter): + """ + Specialized Documenter subclass for attributes that cannot be imported + because they are instance attributes (e.g. assigned in __init__). + """ + objtype = 'instanceattribute' + directivetype = 'attribute' + member_order = 60 + + # must be higher than AttributeDocumenter + priority = 11 + + def __init__(self, *args: Any, **kwargs: Any) -> None: + warnings.warn("%s is deprecated." % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + super().__init__(*args, **kwargs) + + +class SlotsAttributeDocumenter(AttributeDocumenter): + """ + Specialized Documenter subclass for attributes that cannot be imported + because they are attributes in __slots__. + """ + objtype = 'slotsattribute' + directivetype = 'attribute' + member_order = 60 + + # must be higher than AttributeDocumenter + priority = 11 + + def __init__(self, *args: Any, **kwargs: Any) -> None: + warnings.warn("%s is deprecated." % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + super().__init__(*args, **kwargs) + + +class GenericAliasDocumenter(DataDocumenter): + """ + Specialized Documenter subclass for GenericAliases. + """ + + objtype = 'genericalias' + directivetype = 'data' + priority = DataDocumenter.priority + 1 # type: ignore + + def __init__(self, *args: Any, **kwargs: Any) -> None: + warnings.warn("%s is deprecated." % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) + super().__init__(*args, **kwargs) diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py index 9a3428f5d..b4c5fd28d 100644 --- a/sphinx/ext/autodoc/directive.py +++ b/sphinx/ext/autodoc/directive.py @@ -2,7 +2,7 @@ sphinx.ext.autodoc.directive ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -16,7 +16,7 @@ from docutils.statemachine import StringList from docutils.utils import Reporter, assemble_option_dict from sphinx.config import Config -from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.environment import BuildEnvironment from sphinx.ext.autodoc import Documenter, Options from sphinx.util import logging @@ -55,7 +55,7 @@ class DocumenterBridge: def __init__(self, env: BuildEnvironment, reporter: Reporter, options: Options, lineno: int, state: Any = None) -> None: self.env = env - self.reporter = reporter + self._reporter = reporter self.genopt = options self.lineno = lineno self.filename_set = set() # type: Set[str] @@ -74,6 +74,12 @@ class DocumenterBridge: def warn(self, msg: str) -> None: logger.warning(msg, location=(self.env.docname, self.lineno)) + @property + def reporter(self) -> Reporter: + warnings.warn('DocumenterBridge.reporter is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + return self._reporter + def process_documenter_options(documenter: "Type[Documenter]", config: Config, options: Dict ) -> Options: diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index cdccf710d..ffcb27ecc 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -4,23 +4,61 @@ Importer utilities for autodoc - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import importlib import traceback import warnings -from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Tuple +from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Optional, Tuple -from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias -from sphinx.pycode import ModuleAnalyzer +from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning, + deprecated_alias) +from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.util import logging -from sphinx.util.inspect import isclass, isenumclass, safe_getattr +from sphinx.util.inspect import (getannotations, getmro, getslots, isclass, isenumclass, + safe_getattr) + +if False: + # For type annotation + from typing import Type # NOQA + + from sphinx.ext.autodoc import ObjectMember logger = logging.getLogger(__name__) +def mangle(subject: Any, name: str) -> str: + """mangle the given name.""" + try: + if isclass(subject) and name.startswith('__') and not name.endswith('__'): + return "_%s%s" % (subject.__name__, name) + except AttributeError: + pass + + return name + + +def unmangle(subject: Any, name: str) -> Optional[str]: + """unmangle the given name.""" + try: + if isclass(subject) and not name.endswith('__'): + prefix = "_%s__" % subject.__name__ + if name.startswith(prefix): + return name.replace(prefix, "__", 1) + else: + for cls in subject.__mro__: + prefix = "_%s__" % cls.__name__ + if name.startswith(prefix): + # mangled attribute defined in parent class + return None + except AttributeError: + pass + + return name + + def import_module(modname: str, warningiserror: bool = False) -> Any: """ Call importlib.import_module(modname), convert exceptions to ImportError @@ -33,7 +71,7 @@ def import_module(modname: str, warningiserror: bool = False) -> Any: except BaseException as exc: # Importing modules may cause any side effects, including # SystemExit, so we need to catch all errors. - raise ImportError(exc, traceback.format_exc()) + raise ImportError(exc, traceback.format_exc()) from exc def import_object(modname: str, objpath: List[str], objtype: str = '', @@ -68,7 +106,8 @@ def import_object(modname: str, objpath: List[str], objtype: str = '', for attrname in objpath: parent = obj logger.debug('[autodoc] getattr(_, %r)', attrname) - obj = attrgetter(obj, attrname) + mangled_name = mangle(obj, attrname) + obj = attrgetter(obj, mangled_name) logger.debug('[autodoc] => %r', obj) object_name = attrname return [module, parent, object_name, obj] @@ -98,13 +137,16 @@ def import_object(modname: str, objpath: List[str], objtype: str = '', errmsg += '; the following exception was raised:\n%s' % traceback.format_exc() logger.debug(errmsg) - raise ImportError(errmsg) + raise ImportError(errmsg) from exc def get_module_members(module: Any) -> List[Tuple[str, Any]]: """Get members of target module.""" from sphinx.ext.autodoc import INSTANCEATTR + warnings.warn('sphinx.ext.autodoc.importer.get_module_members() is deprecated.', + RemovedInSphinx50Warning) + members = {} # type: Dict[str, Tuple[str, Any]] for name in dir(module): try: @@ -114,10 +156,12 @@ def get_module_members(module: Any) -> List[Tuple[str, Any]]: continue # annotation only member (ex. attr: int) - if hasattr(module, '__annotations__'): - for name in module.__annotations__: + try: + for name in getannotations(module): if name not in members: members[name] = (name, INSTANCEATTR) + except AttributeError: + pass return sorted(list(members.values())) @@ -127,6 +171,18 @@ Attribute = NamedTuple('Attribute', [('name', str), ('value', Any)]) +def _getmro(obj: Any) -> Tuple["Type", ...]: + warnings.warn('sphinx.ext.autodoc.importer._getmro() is deprecated.', + RemovedInSphinx40Warning) + return getmro(obj) + + +def _getannotations(obj: Any) -> Mapping[str, Any]: + warnings.warn('sphinx.ext.autodoc.importer._getannotations() is deprecated.', + RemovedInSphinx40Warning) + return getannotations(obj) + + def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable, analyzer: ModuleAnalyzer = None) -> Dict[str, Attribute]: """Get members and attributes of target object.""" @@ -150,27 +206,36 @@ def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable, members[name] = Attribute(name, True, value) # members in __slots__ - if isclass(subject) and getattr(subject, '__slots__', None) is not None: - from sphinx.ext.autodoc import SLOTSATTR + try: + __slots__ = getslots(subject) + if __slots__: + from sphinx.ext.autodoc import SLOTSATTR - for name in subject.__slots__: - members[name] = Attribute(name, True, SLOTSATTR) + for name in __slots__: + members[name] = Attribute(name, True, SLOTSATTR) + except (AttributeError, TypeError, ValueError): + pass # other members for name in dir(subject): try: value = attrgetter(subject, name) directly_defined = name in obj_dict - if name not in members: + name = unmangle(subject, name) + if name and name not in members: members[name] = Attribute(name, directly_defined, value) except AttributeError: continue # annotation only member (ex. attr: int) - if hasattr(subject, '__annotations__') and isinstance(subject.__annotations__, Mapping): - for name in subject.__annotations__: - if name not in members: - members[name] = Attribute(name, True, INSTANCEATTR) + for i, cls in enumerate(getmro(subject)): + try: + for name in getannotations(cls): + name = unmangle(cls, name) + if name and name not in members: + members[name] = Attribute(name, i == 0, INSTANCEATTR) + except AttributeError: + pass if analyzer: # append instance attributes (cf. self.attr1) if analyzer knows @@ -182,9 +247,84 @@ def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable, return members -from sphinx.ext.autodoc.mock import ( # NOQA - _MockModule, _MockObject, MockFinder, MockLoader, mock -) +def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable + ) -> Dict[str, "ObjectMember"]: + """Get members and attributes of target class.""" + from sphinx.ext.autodoc import INSTANCEATTR, ObjectMember + + # the members directly defined in the class + obj_dict = attrgetter(subject, '__dict__', {}) + + members = {} # type: Dict[str, ObjectMember] + + # enum members + if isenumclass(subject): + for name, value in subject.__members__.items(): + if name not in members: + members[name] = ObjectMember(name, value, class_=subject) + + superclass = subject.__mro__[1] + for name in obj_dict: + if name not in superclass.__dict__: + value = safe_getattr(subject, name) + members[name] = ObjectMember(name, value, class_=subject) + + # members in __slots__ + try: + __slots__ = getslots(subject) + if __slots__: + from sphinx.ext.autodoc import SLOTSATTR + + for name, docstring in __slots__.items(): + members[name] = ObjectMember(name, SLOTSATTR, class_=subject, + docstring=docstring) + except (AttributeError, TypeError, ValueError): + pass + + # other members + for name in dir(subject): + try: + value = attrgetter(subject, name) + unmangled = unmangle(subject, name) + if unmangled and unmangled not in members: + if name in obj_dict: + members[unmangled] = ObjectMember(unmangled, value, class_=subject) + else: + members[unmangled] = ObjectMember(unmangled, value) + except AttributeError: + continue + + try: + for cls in getmro(subject): + # annotation only member (ex. attr: int) + try: + for name in getannotations(cls): + name = unmangle(cls, name) + if name and name not in members: + members[name] = ObjectMember(name, INSTANCEATTR, class_=cls) + except AttributeError: + pass + + # append instance attributes (cf. self.attr1) if analyzer knows + try: + modname = safe_getattr(cls, '__module__') + qualname = safe_getattr(cls, '__qualname__') + analyzer = ModuleAnalyzer.for_module(modname) + analyzer.analyze() + for (ns, name), docstring in analyzer.attr_docs.items(): + if ns == qualname and name not in members: + members[name] = ObjectMember(name, INSTANCEATTR, class_=cls, + docstring='\n'.join(docstring)) + except (AttributeError, PycodeError): + pass + except AttributeError: + pass + + return members + + +from sphinx.ext.autodoc.mock import (MockFinder, MockLoader, _MockModule, _MockObject, # NOQA + mock) deprecated_alias('sphinx.ext.autodoc.importer', { @@ -194,4 +334,11 @@ deprecated_alias('sphinx.ext.autodoc.importer', 'MockLoader': MockLoader, 'mock': mock, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + '_MockModule': 'sphinx.ext.autodoc.mock._MockModule', + '_MockObject': 'sphinx.ext.autodoc.mock._MockObject', + 'MockFinder': 'sphinx.ext.autodoc.mock.MockFinder', + 'MockLoader': 'sphinx.ext.autodoc.mock.MockLoader', + 'mock': 'sphinx.ext.autodoc.mock.mock', + }) diff --git a/sphinx/ext/autodoc/mock.py b/sphinx/ext/autodoc/mock.py index 98a3a3a96..3d4f76410 100644 --- a/sphinx/ext/autodoc/mock.py +++ b/sphinx/ext/autodoc/mock.py @@ -4,7 +4,7 @@ mock for autodoc - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -17,6 +17,7 @@ from types import FunctionType, MethodType, ModuleType from typing import Any, Generator, Iterator, List, Sequence, Tuple, Union from sphinx.util import logging +from sphinx.util.inspect import safe_getattr logger = logging.getLogger(__name__) @@ -52,8 +53,8 @@ class _MockObject: def __mro_entries__(self, bases: Tuple) -> Tuple: return (self.__class__,) - def __getitem__(self, key: str) -> "_MockObject": - return _make_subclass(key, self.__display_name__, self.__class__)() + def __getitem__(self, key: Any) -> "_MockObject": + return _make_subclass(str(key), self.__display_name__, self.__class__)() def __getattr__(self, key: str) -> "_MockObject": return _make_subclass(key, self.__display_name__, self.__class__)() @@ -147,3 +148,27 @@ def mock(modnames: List[str]) -> Generator[None, None, None]: finally: sys.meta_path.remove(finder) finder.invalidate_caches() + + +def ismock(subject: Any) -> bool: + """Check if the object is mocked.""" + # check the object has '__sphinx_mock__' attribute + try: + if safe_getattr(subject, '__sphinx_mock__', None) is None: + return False + except AttributeError: + return False + + # check the object is mocked module + if isinstance(subject, _MockModule): + return True + + try: + # check the object is mocked object + __mro__ = safe_getattr(type(subject), '__mro__', []) + if len(__mro__) > 2 and __mro__[1] is _MockObject: + return True + except AttributeError: + pass + + return False diff --git a/sphinx/ext/autodoc/type_comment.py b/sphinx/ext/autodoc/type_comment.py index e6a77f24d..4db13c695 100644 --- a/sphinx/ext/autodoc/type_comment.py +++ b/sphinx/ext/autodoc/type_comment.py @@ -4,13 +4,12 @@ Update annotations info of living objects using type_comments. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from inspect import Parameter, Signature, getsource -from typing import Any, Dict, List -from typing import cast +from typing import Any, Dict, List, cast import sphinx from sphinx.application import Sphinx @@ -18,8 +17,7 @@ from sphinx.locale import __ from sphinx.pycode.ast import ast from sphinx.pycode.ast import parse as ast_parse from sphinx.pycode.ast import unparse as ast_unparse -from sphinx.util import inspect -from sphinx.util import logging +from sphinx.util import inspect, logging logger = logging.getLogger(__name__) @@ -128,6 +126,9 @@ def update_annotations_using_type_comments(app: Sphinx, obj: Any, bound_method: if 'return' not in obj.__annotations__: obj.__annotations__['return'] = type_sig.return_annotation + except KeyError as exc: + logger.warning(__("Failed to update signature for %r: parameter not found: %s"), + obj, exc) except NotImplementedError as exc: # failed to ast.unparse() logger.warning(__("Failed to parse type_comment for %r: %s"), obj, exc) diff --git a/sphinx/ext/autodoc/typehints.py b/sphinx/ext/autodoc/typehints.py index b763bdfc7..533b71e42 100644 --- a/sphinx/ext/autodoc/typehints.py +++ b/sphinx/ext/autodoc/typehints.py @@ -4,14 +4,13 @@ Generating content for autodoc using typehints - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re from collections import OrderedDict -from typing import Any, Dict, Iterable -from typing import cast +from typing import Any, Dict, Iterable, cast from docutils import nodes from docutils.nodes import Element @@ -28,7 +27,7 @@ def record_typehints(app: Sphinx, objtype: str, name: str, obj: Any, if callable(obj): annotations = app.env.temp_data.setdefault('annotations', {}) annotation = annotations.setdefault(name, OrderedDict()) - sig = inspect.signature(obj) + sig = inspect.signature(obj, type_aliases=app.config.autodoc_type_aliases) for param in sig.parameters.values(): if param.annotation is not param.empty: annotation[param.name] = typing.stringify(param.annotation) @@ -46,11 +45,16 @@ def merge_typehints(app: Sphinx, domain: str, objtype: str, contentnode: Element if objtype == 'class' and app.config.autoclass_content not in ('init', 'both'): return - signature = cast(addnodes.desc_signature, contentnode.parent[0]) - if signature['module']: - fullname = '.'.join([signature['module'], signature['fullname']]) - else: - fullname = signature['fullname'] + try: + signature = cast(addnodes.desc_signature, contentnode.parent[0]) + if signature['module']: + fullname = '.'.join([signature['module'], signature['fullname']]) + else: + fullname = signature['fullname'] + except KeyError: + # signature node does not have valid context info for the target object + return + annotations = app.env.temp_data.get('annotations', {}) if annotations.get(fullname, {}): field_lists = [n for n in contentnode if isinstance(n, nodes.field_list)] diff --git a/sphinx/ext/autosectionlabel.py b/sphinx/ext/autosectionlabel.py index 4bb401791..be8ad0bc1 100644 --- a/sphinx/ext/autosectionlabel.py +++ b/sphinx/ext/autosectionlabel.py @@ -4,12 +4,11 @@ Allow reference sections by :ref: role using its title. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict -from typing import cast +from typing import Any, Dict, cast from docutils import nodes from docutils.nodes import Node @@ -20,7 +19,6 @@ from sphinx.locale import __ from sphinx.util import logging from sphinx.util.nodes import clean_astext - logger = logging.getLogger(__name__) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 162b6868c..b268127d0 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -48,7 +48,7 @@ resolved to a Python object, and otherwise it becomes simple emphasis. This can be used as the default role to make links 'smart'. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -60,8 +60,7 @@ import sys import warnings from os import path from types import ModuleType -from typing import Any, Dict, List, Tuple -from typing import cast +from typing import Any, Dict, List, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node, system_message @@ -72,19 +71,19 @@ from docutils.statemachine import StringList import sphinx from sphinx import addnodes from sphinx.application import Sphinx +from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.environment import BuildEnvironment from sphinx.environment.adapters.toctree import TocTree -from sphinx.ext.autodoc import Documenter +from sphinx.ext.autodoc import INSTANCEATTR, Documenter from sphinx.ext.autodoc.directive import DocumenterBridge, Options from sphinx.ext.autodoc.importer import import_module from sphinx.ext.autodoc.mock import mock from sphinx.locale import __ from sphinx.pycode import ModuleAnalyzer, PycodeError -from sphinx.util import rst, logging -from sphinx.util.docutils import ( - NullReporter, SphinxDirective, SphinxRole, new_document, switch_source_input -) +from sphinx.util import logging, rst +from sphinx.util.docutils import (NullReporter, SphinxDirective, SphinxRole, new_document, + switch_source_input) from sphinx.util.matching import Matcher from sphinx.writers.html import HTMLTranslator @@ -99,6 +98,8 @@ logger = logging.getLogger(__name__) periods_re = re.compile(r'\.(?:\s+)') literal_re = re.compile(r'::\s*$') +WELL_KNOWN_ABBREVIATIONS = ('et al.', ' i.e.',) + # -- autosummary_toc node ------------------------------------------------------ @@ -175,8 +176,10 @@ class FakeDirective(DocumenterBridge): def __init__(self) -> None: settings = Struct(tab_width=8) document = Struct(settings=settings) + env = BuildEnvironment() + env.config = Config() state = Struct(document=document) - super().__init__({}, None, Options(), 0, state) # type: ignore + super().__init__(env, None, Options(), 0, state) def get_documenter(app: Sphinx, obj: Any, parent: Any) -> "Type[Documenter]": @@ -250,7 +253,9 @@ class Autosummary(SphinxDirective): tree_prefix = self.options['toctree'].strip() docnames = [] excluded = Matcher(self.config.exclude_patterns) + filename_map = self.config.autosummary_filename_map for name, sig, summary, real_name in items: + real_name = filename_map.get(real_name, real_name) docname = posixpath.join(tree_prefix, real_name) docname = posixpath.normpath(posixpath.join(dirname, docname)) if docname not in self.env.found_docs: @@ -281,6 +286,29 @@ class Autosummary(SphinxDirective): return nodes + def import_by_name(self, name: str, prefixes: List[str]) -> Tuple[str, Any, Any, str]: + with mock(self.config.autosummary_mock_imports): + try: + return import_by_name(name, prefixes) + except ImportError as exc: + # check existence of instance attribute + try: + return import_ivar_by_name(name, prefixes) + except ImportError: + pass + + raise exc # re-raise ImportError if instance attribute not found + + def create_documenter(self, app: Sphinx, obj: Any, + parent: Any, full_name: str) -> "Documenter": + """Get an autodoc.Documenter class suitable for documenting the given + object. + + Wraps get_documenter and is meant as a hook for extensions. + """ + doccls = get_documenter(app, obj, parent) + return doccls(self.bridge, full_name) + def get_items(self, names: List[str]) -> List[Tuple[str, str, str, str]]: """Try to import the given names, and return a list of ``[(name, signature, summary_string, real_name), ...]``. @@ -298,8 +326,7 @@ class Autosummary(SphinxDirective): display_name = name.split('.')[-1] try: - with mock(self.config.autosummary_mock_imports): - real_name, obj, parent, modname = import_by_name(name, prefixes=prefixes) + real_name, obj, parent, modname = self.import_by_name(name, prefixes=prefixes) except ImportError: logger.warning(__('autosummary: failed to import %s'), name, location=self.get_source_info()) @@ -313,8 +340,7 @@ class Autosummary(SphinxDirective): full_name = modname + '::' + full_name[len(modname) + 1:] # NB. using full_name here is important, since Documenters # handle module prefixes slightly differently - doccls = get_documenter(self.env.app, obj, parent) - documenter = doccls(self.bridge, full_name) + documenter = self.create_documenter(self.env.app, obj, parent, full_name) if not documenter.parse_name(): logger.warning(__('failed to parse name %s'), real_name, location=self.get_source_info()) @@ -497,6 +523,13 @@ def mangle_signature(sig: str, max_chars: int = 30) -> str: def extract_summary(doc: List[str], document: Any) -> str: """Extract summary from docstring.""" + def parse(doc: List[str], settings: Any) -> nodes.document: + state_machine = RSTStateMachine(state_classes, 'Body') + node = new_document('', settings) + node.reporter = NullReporter() + state_machine.run(doc, node) + + return node # Skip a blank lines at the top while doc and not doc[0].strip(): @@ -514,11 +547,7 @@ def extract_summary(doc: List[str], document: Any) -> str: return '' # parse the docstring - state_machine = RSTStateMachine(state_classes, 'Body') - node = new_document('', document.settings) - node.reporter = NullReporter() - state_machine.run(doc, node) - + node = parse(doc, document.settings) if not isinstance(node[0], nodes.paragraph): # document starts with non-paragraph: pick up the first line summary = doc[0].strip() @@ -529,11 +558,13 @@ def extract_summary(doc: List[str], document: Any) -> str: summary = sentences[0].strip() else: summary = '' - while sentences: - summary += sentences.pop(0) + '.' + for i in range(len(sentences)): + summary = ". ".join(sentences[:i + 1]).rstrip(".") + "." node[:] = [] - state_machine.run([summary], node) - if not node.traverse(nodes.system_message): + node = parse(doc, document.settings) + if summary.endswith(WELL_KNOWN_ABBREVIATIONS): + pass + elif not node.traverse(nodes.system_message): # considered as that splitting by period does not break inline markups break @@ -647,7 +678,24 @@ def _import_by_name(name: str) -> Tuple[Any, Any, str]: else: return sys.modules[modname], None, modname except (ValueError, ImportError, AttributeError, KeyError) as e: - raise ImportError(*e.args) + raise ImportError(*e.args) from e + + +def import_ivar_by_name(name: str, prefixes: List[str] = [None]) -> Tuple[str, Any, Any, str]: + """Import an instance variable that has the given *name*, under one of the + *prefixes*. The first name that succeeds is used. + """ + try: + name, attr = name.rsplit(".", 1) + real_name, obj, parent, modname = import_by_name(name, prefixes) + qualname = real_name.replace(modname + ".", "") + analyzer = ModuleAnalyzer.for_module(modname) + if (qualname, attr) in analyzer.find_attr_docs(): + return real_name + "." + attr, INSTANCEATTR, obj, modname + except (ImportError, ValueError, PycodeError): + pass + + raise ImportError # -- :autolink: (smart default role) ------------------------------------------- @@ -755,7 +803,8 @@ def process_generate_options(app: Sphinx) -> None: with mock(app.config.autosummary_mock_imports): generate_autosummary_docs(genfiles, suffix=suffix, base_path=app.srcdir, app=app, imported_members=imported_members, - overwrite=app.config.autosummary_generate_overwrite) + overwrite=app.config.autosummary_generate_overwrite, + encoding=app.config.source_encoding) def setup(app: Sphinx) -> Dict[str, Any]: @@ -777,6 +826,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_role('autolink', AutoLink()) 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_overwrite', True, False) app.add_config_value('autosummary_mock_imports', diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 4dde73829..0240d2c7c 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -13,7 +13,7 @@ generate: sphinx-autogen -o source/generated source/*.rst - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -34,20 +34,18 @@ from jinja2 import TemplateNotFound from jinja2.sandbox import SandboxedEnvironment import sphinx.locale -from sphinx import __display_version__ -from sphinx import package_dir +from sphinx import __display_version__, package_dir from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.ext.autodoc import Documenter -from sphinx.ext.autosummary import import_by_name, get_documenter +from sphinx.ext.autodoc.importer import import_module +from sphinx.ext.autosummary import get_documenter, import_by_name, import_ivar_by_name from sphinx.locale import __ from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.registry import SphinxComponentRegistry -from sphinx.util import logging -from sphinx.util import rst -from sphinx.util import split_full_qualified_name +from sphinx.util import logging, rst, split_full_qualified_name from sphinx.util.inspect import safe_getattr from sphinx.util.osutil import ensuredir from sphinx.util.template import SphinxTemplateLoader @@ -74,6 +72,7 @@ class DummyApplication: self.warningiserror = False self.config.add('autosummary_context', {}, True, None) + self.config.add('autosummary_filename_map', {}, True, None) self.config.init_values() def emit_firstresult(self, *args: Any) -> None: @@ -87,29 +86,29 @@ AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str), def setup_documenters(app: Any) -> None: - from sphinx.ext.autodoc import ( - ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, - FunctionDocumenter, MethodDocumenter, AttributeDocumenter, - InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, - SlotsAttributeDocumenter, DataDeclarationDocumenter, GenericAliasDocumenter, - SingledispatchFunctionDocumenter, - ) + from sphinx.ext.autodoc import (AttributeDocumenter, ClassDocumenter, DataDocumenter, + DecoratorDocumenter, ExceptionDocumenter, + FunctionDocumenter, MethodDocumenter, ModuleDocumenter, + NewTypeAttributeDocumenter, NewTypeDataDocumenter, + PropertyDocumenter) documenters = [ ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, - FunctionDocumenter, MethodDocumenter, AttributeDocumenter, - InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, - SlotsAttributeDocumenter, DataDeclarationDocumenter, GenericAliasDocumenter, - SingledispatchFunctionDocumenter, + FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter, + NewTypeDataDocumenter, AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, ] # type: List[Type[Documenter]] for documenter in documenters: app.registry.add_documenter(documenter.objtype, documenter) def _simple_info(msg: str) -> None: + warnings.warn('_simple_info() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) print(msg) def _simple_warn(msg: str) -> None: + warnings.warn('_simple_warn() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) print('WARNING: ' + msg, file=sys.stderr) @@ -143,11 +142,11 @@ class AutosummaryRenderer: if isinstance(app, (Sphinx, DummyApplication)): if app.translator: self.env.add_extension("jinja2.ext.i18n") - self.env.install_gettext_translations(app.translator) # type: ignore + self.env.install_gettext_translations(app.translator) 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 + self.env.install_gettext_translations(app.app.translator) def exists(self, template_name: str) -> bool: """Check if template file exists.""" @@ -230,7 +229,8 @@ class ModuleScanner: def generate_autosummary_content(name: str, obj: Any, parent: Any, template: AutosummaryRenderer, template_name: str, imported_members: bool, app: Any, - recursive: bool, context: Dict) -> str: + recursive: bool, context: Dict, + modname: str = None, qualname: str = None) -> str: doc = get_documenter(app, obj, parent) def skip_member(obj: Any, name: str, objtype: str) -> bool: @@ -289,6 +289,13 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, items = [] # type: List[str] for _, modname, ispkg in pkgutil.iter_modules(obj.__path__): fullname = name + '.' + modname + try: + module = import_module(fullname) + if module and hasattr(module, '__sphinx_mock__'): + continue + except ImportError: + pass + items.append(fullname) public = [x for x in items if not x.split('.')[-1].startswith('_')] return public, items @@ -319,7 +326,9 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, ns['attributes'], ns['all_attributes'] = \ get_members(obj, {'attribute', 'property'}) - modname, qualname = split_full_qualified_name(name) + if modname is None or qualname is None: + modname, qualname = split_full_qualified_name(name) + if doc.objtype in ('method', 'attribute', 'property'): ns['class'] = qualname.rsplit(".", 1)[0] @@ -347,7 +356,7 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, info: Callable = None, base_path: str = None, builder: Builder = None, template_dir: str = None, imported_members: bool = False, app: Any = None, - overwrite: bool = True) -> None: + overwrite: bool = True, encoding: str = 'utf-8') -> None: if info: warnings.warn('info argument for generate_autosummary_docs() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) @@ -390,6 +399,11 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, # keep track of new files new_files = [] + if app: + filename_map = app.config.autosummary_filename_map + else: + filename_map = {} + # write for entry in sorted(set(items), key=str): if entry.path is None: @@ -401,31 +415,38 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, ensuredir(path) try: - name, obj, parent, mod_name = import_by_name(entry.name) + name, obj, parent, modname = import_by_name(entry.name) + qualname = name.replace(modname + ".", "") except ImportError as e: - _warn(__('[autosummary] failed to import %r: %s') % (entry.name, e)) - continue + try: + # try to importl as an instance attribute + name, obj, parent, modname = import_ivar_by_name(entry.name) + qualname = name.replace(modname + ".", "") + except ImportError: + _warn(__('[autosummary] failed to import %r: %s') % (entry.name, e)) + continue context = {} if app: context.update(app.config.autosummary_context) content = generate_autosummary_content(name, obj, parent, template, entry.template, - imported_members, app, entry.recursive, context) + imported_members, app, entry.recursive, context, + modname, qualname) - filename = os.path.join(path, name + suffix) + filename = os.path.join(path, filename_map.get(name, name) + suffix) if os.path.isfile(filename): - with open(filename) as f: + with open(filename, encoding=encoding) as f: old_content = f.read() if content == old_content: continue elif overwrite: # content has changed - with open(filename, 'w') as f: + with open(filename, 'w', encoding=encoding) as f: f.write(content) new_files.append(filename) else: - with open(filename, 'w') as f: + with open(filename, 'w', encoding=encoding) as f: f.write(content) new_files.append(filename) diff --git a/sphinx/ext/autosummary/templates/autosummary/module.rst b/sphinx/ext/autosummary/templates/autosummary/module.rst index 3a93e872a..e74c012f4 100644 --- a/sphinx/ext/autosummary/templates/autosummary/module.rst +++ b/sphinx/ext/autosummary/templates/autosummary/module.rst @@ -4,7 +4,7 @@ {% block attributes %} {% if attributes %} - .. rubric:: Module Attributes + .. rubric:: {{ _('Module Attributes') }} .. autosummary:: {% for item in attributes %} diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index e8157848f..f052b8810 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -5,7 +5,7 @@ Check Python modules and C API for coverage. Mostly written by Josip Dzolonga for the Google Highly Open Participation contest. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -15,13 +15,14 @@ import pickle import re from importlib import import_module from os import path -from typing import Any, Dict, IO, List, Pattern, Set, Tuple +from typing import IO, Any, Dict, List, Pattern, Set, Tuple import sphinx from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.locale import __ from sphinx.util import logging +from sphinx.util.console import red # type: ignore from sphinx.util.inspect import safe_getattr logger = logging.getLogger(__name__) @@ -121,6 +122,14 @@ class CoverageBuilder(Builder): write_header(op, filename) for typ, name in sorted(undoc): op.write(' * %-50s [%9s]\n' % (name, typ)) + if self.config.coverage_show_missing_items: + if self.app.quiet or self.app.warningiserror: + logger.warning(__('undocumented c api: %s [%s] in file %s'), + name, typ, filename) + else: + logger.info(red('undocumented ') + 'c ' + 'api ' + + '%-30s' % (name + " [%9s]" % typ) + + red(' - in file ') + filename) op.write('\n') def ignore_pyobj(self, full_name: str) -> bool: @@ -239,16 +248,48 @@ class CoverageBuilder(Builder): if undoc['funcs']: op.write('Functions:\n') op.writelines(' * %s\n' % x for x in undoc['funcs']) + if self.config.coverage_show_missing_items: + if self.app.quiet or self.app.warningiserror: + for func in undoc['funcs']: + logger.warning( + __('undocumented python function: %s :: %s'), + name, func) + else: + for func in undoc['funcs']: + logger.info(red('undocumented ') + 'py ' + 'function ' + + '%-30s' % func + red(' - in module ') + name) op.write('\n') if undoc['classes']: op.write('Classes:\n') - for name, methods in sorted( + for class_name, methods in sorted( undoc['classes'].items()): if not methods: - op.write(' * %s\n' % name) + op.write(' * %s\n' % class_name) + if self.config.coverage_show_missing_items: + if self.app.quiet or self.app.warningiserror: + logger.warning( + __('undocumented python class: %s :: %s'), + name, class_name) + else: + logger.info(red('undocumented ') + 'py ' + + 'class ' + '%-30s' % class_name + + red(' - in module ') + name) else: - op.write(' * %s -- missing methods:\n\n' % name) + op.write(' * %s -- missing methods:\n\n' % class_name) op.writelines(' - %s\n' % x for x in methods) + if self.config.coverage_show_missing_items: + if self.app.quiet or self.app.warningiserror: + for meth in methods: + logger.warning( + __('undocumented python method:' + + ' %s :: %s :: %s'), + name, class_name, meth) + else: + for meth in methods: + logger.info(red('undocumented ') + 'py ' + + 'method ' + '%-30s' % + (class_name + '.' + meth) + + red(' - in module ') + name) op.write('\n') if failed: @@ -273,4 +314,5 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('coverage_ignore_c_items', {}, False) app.add_config_value('coverage_write_headline', True, False) app.add_config_value('coverage_skip_undoc_in_source', False, False) + app.add_config_value('coverage_show_missing_items', False, False) return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 26966016d..20afa2ec6 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -5,7 +5,7 @@ Mimic doctest by automatically executing code snippets and checking their results. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -21,7 +21,7 @@ from typing import Any, Callable, Dict, Iterable, List, Sequence, Set, Tuple from docutils import nodes from docutils.nodes import Element, Node, TextElement from docutils.parsers.rst import directives -from packaging.specifiers import SpecifierSet, InvalidSpecifier +from packaging.specifiers import InvalidSpecifier, SpecifierSet from packaging.version import Version import sphinx @@ -36,6 +36,7 @@ from sphinx.util.osutil import relpath if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx @@ -91,7 +92,7 @@ class TestDirective(SphinxDirective): # convert <BLANKLINE>s to ordinary blank lines for presentation test = code code = blankline_re.sub('', code) - if doctestopt_re.search(code): + if doctestopt_re.search(code) and 'no-trim-doctest-flags' not in self.options: if not test: test = code code = doctestopt_re.sub('', code) @@ -151,6 +152,10 @@ class TestDirective(SphinxDirective): line=self.lineno) if 'skipif' in self.options: node['skipif'] = self.options['skipif'] + if 'trim-doctest-flags' in self.options: + node['trim_flags'] = True + elif 'no-trim-doctest-flags' in self.options: + node['trim_flags'] = False return [node] @@ -165,26 +170,32 @@ class TestcleanupDirective(TestDirective): class DoctestDirective(TestDirective): option_spec = { 'hide': directives.flag, + 'no-trim-doctest-flags': directives.flag, 'options': directives.unchanged, 'pyversion': directives.unchanged_required, 'skipif': directives.unchanged_required, + 'trim-doctest-flags': directives.flag, } class TestcodeDirective(TestDirective): option_spec = { 'hide': directives.flag, + 'no-trim-doctest-flags': directives.flag, 'pyversion': directives.unchanged_required, 'skipif': directives.unchanged_required, + 'trim-doctest-flags': directives.flag, } class TestoutputDirective(TestDirective): option_spec = { 'hide': directives.flag, + 'no-trim-doctest-flags': directives.flag, 'options': directives.unchanged, 'pyversion': directives.unchanged_required, 'skipif': directives.unchanged_required, + 'trim-doctest-flags': directives.flag, } diff --git a/sphinx/ext/duration.py b/sphinx/ext/duration.py index 669baf2f1..f714dedfb 100644 --- a/sphinx/ext/duration.py +++ b/sphinx/ext/duration.py @@ -4,15 +4,14 @@ Measure durations of Sphinx processing. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from datetime import datetime, timedelta from itertools import islice from operator import itemgetter -from typing import Any, Dict, List -from typing import cast +from typing import Any, Dict, List, cast from docutils import nodes diff --git a/sphinx/ext/extlinks.py b/sphinx/ext/extlinks.py index ff3adb357..d82c0378b 100644 --- a/sphinx/ext/extlinks.py +++ b/sphinx/ext/extlinks.py @@ -19,7 +19,7 @@ You can also give an explicit caption, e.g. :exmpl:`Foo <foo>`. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/githubpages.py b/sphinx/ext/githubpages.py index 4564ce60e..e760bb4b6 100644 --- a/sphinx/ext/githubpages.py +++ b/sphinx/ext/githubpages.py @@ -4,7 +4,7 @@ To publish HTML docs at GitHub Pages, create .nojekyll file. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py index c21868a6f..402b7c990 100644 --- a/sphinx/ext/graphviz.py +++ b/sphinx/ext/graphviz.py @@ -5,7 +5,7 @@ Allow graphviz-formatted graphs to be included in Sphinx-generated documents inline. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,7 +13,7 @@ import posixpath import re import subprocess from os import path -from subprocess import CalledProcessError, PIPE +from subprocess import PIPE, CalledProcessError from typing import Any, Dict, List, Tuple from docutils import nodes @@ -182,7 +182,8 @@ class GraphvizSimple(SphinxDirective): 'alt': directives.unchanged, 'align': align_spec, 'caption': directives.unchanged, - 'graphviz_dot': directives.unchanged, + 'layout': directives.unchanged, + 'graphviz_dot': directives.unchanged, # an old alias of `layout` option 'name': directives.unchanged, 'class': directives.class_option, } @@ -194,6 +195,8 @@ class GraphvizSimple(SphinxDirective): node['options'] = {'docname': self.env.docname} if 'graphviz_dot' in self.options: node['options']['graphviz_dot'] = self.options['graphviz_dot'] + if 'layout' in self.options: + node['options']['graphviz_dot'] = self.options['layout'] if 'alt' in self.options: node['alt'] = self.options['alt'] if 'align' in self.options: @@ -256,7 +259,7 @@ def render_dot(self: SphinxTranslator, code: str, options: Dict, return None, None except CalledProcessError as exc: raise GraphvizError(__('dot exited with error:\n[stderr]\n%r\n' - '[stdout]\n%r') % (exc.stderr, exc.stdout)) + '[stdout]\n%r') % (exc.stderr, exc.stdout)) from exc def render_dot_html(self: HTMLTranslator, node: graphviz, code: str, options: Dict, @@ -270,7 +273,7 @@ def render_dot_html(self: HTMLTranslator, node: graphviz, code: str, options: Di fname, outfn = render_dot(self, code, options, format, prefix) except GraphvizError as exc: logger.warning(__('dot code %r: %s'), code, exc) - raise nodes.SkipNode + raise nodes.SkipNode from exc classes = [imgcls, 'graphviz'] + node.get('classes', []) imgcls = ' '.join(filter(None, classes)) @@ -321,7 +324,7 @@ def render_dot_latex(self: LaTeXTranslator, node: graphviz, code: str, fname, outfn = render_dot(self, code, options, 'pdf', prefix) except GraphvizError as exc: logger.warning(__('dot code %r: %s'), code, exc) - raise nodes.SkipNode + raise nodes.SkipNode from exc is_inline = self.is_inline(node) @@ -358,7 +361,7 @@ def render_dot_texinfo(self: TexinfoTranslator, node: graphviz, code: str, fname, outfn = render_dot(self, code, options, 'png', prefix) except GraphvizError as exc: logger.warning(__('dot code %r: %s'), code, exc) - raise nodes.SkipNode + raise nodes.SkipNode from exc if fname is not None: self.body.append('@image{%s,,,[graphviz],png}\n' % fname[:-4]) raise nodes.SkipNode @@ -385,7 +388,7 @@ def man_visit_graphviz(self: ManualPageTranslator, node: graphviz) -> None: def on_build_finished(app: Sphinx, exc: Exception) -> None: - if exc is None: + if exc is None and app.builder.format == 'html': src = path.join(sphinx.package_dir, 'templates', 'graphviz', 'graphviz.css') dst = path.join(app.outdir, '_static') copy_asset(src, dst) diff --git a/sphinx/ext/ifconfig.py b/sphinx/ext/ifconfig.py index 0e652509f..df8545028 100644 --- a/sphinx/ext/ifconfig.py +++ b/sphinx/ext/ifconfig.py @@ -15,7 +15,7 @@ namespace of the project configuration (that is, all variables from ``conf.py`` are available.) - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -62,7 +62,7 @@ def process_ifconfig_nodes(app: Sphinx, doctree: nodes.document, docname: str) - # handle exceptions in a clean fashion from traceback import format_exception_only msg = ''.join(format_exception_only(err.__class__, err)) - newnode = doctree.reporter.error('Exception occured in ' + newnode = doctree.reporter.error('Exception occurred in ' 'ifconfig expression: \n%s' % msg, base_node=node) node.replace_self(newnode) diff --git a/sphinx/ext/imgconverter.py b/sphinx/ext/imgconverter.py index bf4b9b9d1..b0d40b551 100644 --- a/sphinx/ext/imgconverter.py +++ b/sphinx/ext/imgconverter.py @@ -4,13 +4,13 @@ Image converter extension for Sphinx - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import subprocess import sys -from subprocess import CalledProcessError, PIPE +from subprocess import PIPE, CalledProcessError from typing import Any, Dict from sphinx.application import Sphinx @@ -19,7 +19,6 @@ from sphinx.locale import __ from sphinx.transforms.post_transforms.images import ImageConverter from sphinx.util import logging - logger = logging.getLogger(__name__) @@ -70,7 +69,7 @@ class ImagemagickConverter(ImageConverter): except CalledProcessError as exc: raise ExtensionError(__('convert exited with error:\n' '[stderr]\n%r\n[stdout]\n%r') % - (exc.stderr, exc.stdout)) + (exc.stderr, exc.stdout)) from exc def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py index 2050e470e..cef50d548 100644 --- a/sphinx/ext/imgmath.py +++ b/sphinx/ext/imgmath.py @@ -4,7 +4,7 @@ Render math in HTML via dvipng or dvisvgm. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -15,7 +15,7 @@ import subprocess import sys import tempfile from os import path -from subprocess import CalledProcessError, PIPE +from subprocess import PIPE, CalledProcessError from typing import Any, Dict, List, Tuple from docutils import nodes @@ -93,7 +93,7 @@ depthsvgcomment_re = re.compile(r'<!-- DEPTH=(-?\d+) -->') def read_svg_depth(filename: str) -> int: """Read the depth from comment at last line of SVG file """ - with open(filename, 'r') as f: + with open(filename) as f: for line in f: pass # Only last line is checked @@ -165,13 +165,13 @@ def compile_math(latex: str, builder: Builder) -> str: try: subprocess.run(command, stdout=PIPE, stderr=PIPE, cwd=tempdir, check=True) return path.join(tempdir, 'math.dvi') - except OSError: + except OSError as exc: logger.warning(__('LaTeX command %r cannot be run (needed for math ' 'display), check the imgmath_latex setting'), builder.config.imgmath_latex) - raise InvokeError + raise InvokeError from exc except CalledProcessError as exc: - raise MathExtError('latex exited with error', exc.stderr, exc.stdout) + raise MathExtError('latex exited with error', exc.stderr, exc.stdout) from exc def convert_dvi_to_image(command: List[str], name: str) -> Tuple[bytes, bytes]: @@ -179,13 +179,13 @@ def convert_dvi_to_image(command: List[str], name: str) -> Tuple[bytes, bytes]: try: ret = subprocess.run(command, stdout=PIPE, stderr=PIPE, check=True) return ret.stdout, ret.stderr - except OSError: + except OSError as exc: logger.warning(__('%s command %r cannot be run (needed for math ' 'display), check the imgmath_%s setting'), name, command[0], name) - raise InvokeError + raise InvokeError from exc except CalledProcessError as exc: - raise MathExtError('%s exited with error' % name, exc.stderr, exc.stdout) + raise MathExtError('%s exited with error' % name, exc.stderr, exc.stdout) from exc def convert_dvi_to_png(dvipath: str, builder: Builder) -> Tuple[str, int]: @@ -326,7 +326,7 @@ def html_visit_math(self: HTMLTranslator, node: nodes.math) -> None: backrefs=[], source=node.astext()) sm.walkabout(self) logger.warning(__('display latex %r: %s'), node.astext(), msg) - raise nodes.SkipNode + raise nodes.SkipNode from exc if fname is None: # something failed -- use text-only as a bad substitute self.body.append('<span class="math">%s</span>' % @@ -352,7 +352,7 @@ def html_visit_displaymath(self: HTMLTranslator, node: nodes.math_block) -> None backrefs=[], source=node.astext()) sm.walkabout(self) logger.warning(__('inline latex %r: %s'), node.astext(), msg) - raise nodes.SkipNode + raise nodes.SkipNode from exc self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append('<p>') if node['number']: diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index 7b2383fca..63a171087 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -31,7 +31,7 @@ r""" The graph is inserted as a PNG+image map into HTML and a PDF in LaTeX. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -39,8 +39,7 @@ import builtins import inspect import re from importlib import import_module -from typing import Any, Dict, Iterable, List, Tuple -from typing import cast +from typing import Any, Dict, Iterable, List, Tuple, cast from docutils import nodes from docutils.nodes import Node @@ -50,22 +49,23 @@ import sphinx from sphinx import addnodes from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment -from sphinx.ext.graphviz import ( - graphviz, figure_wrapper, - render_dot_html, render_dot_latex, render_dot_texinfo -) +from sphinx.ext.graphviz import (figure_wrapper, graphviz, render_dot_html, render_dot_latex, + render_dot_texinfo) from sphinx.util import md5 from sphinx.util.docutils import SphinxDirective from sphinx.writers.html import HTMLTranslator from sphinx.writers.latex import LaTeXTranslator from sphinx.writers.texinfo import TexinfoTranslator - module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names (\w+) \s* $ # class/final module name ''', re.VERBOSE) +py_builtins = [obj for obj in vars(builtins).values() + if inspect.isclass(obj)] + + def try_import(objname: str) -> Any: """Import a object or module using *name* and *currentmodule*. *name* should be a relative name from *currentmodule* or @@ -178,7 +178,6 @@ class InheritanceGraph: traverse to. Multiple names can be specified separated by comma. """ all_classes = {} - py_builtins = vars(builtins).values() def recurse(cls: Any) -> None: if not show_builtins and cls in py_builtins: diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 02f605bac..5569ad9de 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -19,7 +19,7 @@ also be specified individually, e.g. if the docs should be buildable without Internet access. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -29,7 +29,7 @@ import posixpath import sys import time from os import path -from typing import Any, Dict, IO, List, Tuple +from typing import IO, Any, Dict, List, Tuple from urllib.parse import urlsplit, urlunsplit from docutils import nodes @@ -42,11 +42,10 @@ from sphinx.builders.html import INVENTORY_FILENAME from sphinx.config import Config from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ -from sphinx.util import requests, logging +from sphinx.util import logging, requests from sphinx.util.inventory import InventoryFile from sphinx.util.typing import Inventory - logger = logging.getLogger(__name__) @@ -179,7 +178,7 @@ def fetch_inventory(app: Sphinx, uri: str, inv: Any) -> Any: join = path.join if localuri else posixpath.join invdata = InventoryFile.load(f, uri, join) except ValueError as exc: - raise ValueError('unknown or unsupported inventory version: %r' % exc) + raise ValueError('unknown or unsupported inventory version: %r' % exc) from exc except Exception as err: err.args = ('intersphinx inventory %r not readable due to %s: %s', inv, err.__class__.__name__, str(err)) diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index 75369a5ca..cec40e224 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -5,18 +5,15 @@ Set up everything for use of JSMath to display math in HTML via JavaScript. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import warnings from typing import Any, Dict -from sphinxcontrib.jsmath import ( # NOQA - html_visit_math, - html_visit_displaymath, - install_jsmath, -) +from sphinxcontrib.jsmath import (html_visit_displaymath, html_visit_math, # NOQA + install_jsmath) import sphinx from sphinx.application import Sphinx diff --git a/sphinx/ext/linkcode.py b/sphinx/ext/linkcode.py index 68e8603f7..5c118a9fb 100644 --- a/sphinx/ext/linkcode.py +++ b/sphinx/ext/linkcode.py @@ -4,7 +4,7 @@ Add external links to module code in Python object descriptions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index cc3cd4ba3..ff8ef3718 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -6,26 +6,28 @@ Sphinx's HTML writer -- requires the MathJax JavaScript library on your webserver/computer. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import json -from typing import Any, Dict -from typing import cast +from typing import Any, Dict, cast from docutils import nodes import sphinx from sphinx.application import Sphinx -from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.domains.math import MathDomain -from sphinx.environment import BuildEnvironment from sphinx.errors import ExtensionError from sphinx.locale import _ from sphinx.util.math import get_node_equation_number from sphinx.writers.html import HTMLTranslator +# more information for mathjax secure url is here: +# https://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn +MATHJAX_URL = ('https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?' + 'config=TeX-AMS-MML_HTMLorMML') + def html_visit_math(self: HTMLTranslator, node: nodes.math) -> None: self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate nohighlight')) @@ -67,25 +69,25 @@ def html_visit_displaymath(self: HTMLTranslator, node: nodes.math_block) -> None raise nodes.SkipNode -def install_mathjax(app: Sphinx, env: BuildEnvironment) -> None: +def install_mathjax(app: Sphinx, pagename: str, templatename: str, context: Dict, + event_arg: Any) -> None: if app.builder.format != 'html' or app.builder.math_renderer_name != 'mathjax': # type: ignore # NOQA return if not app.config.mathjax_path: raise ExtensionError('mathjax_path config value must be set for the ' 'mathjax extension to work') - builder = cast(StandaloneHTMLBuilder, app.builder) - domain = cast(MathDomain, env.get_domain('math')) - if domain.has_equations(): + domain = cast(MathDomain, app.env.get_domain('math')) + if domain.has_equations(pagename): # Enable mathjax only if equations exists options = {'async': 'async'} if app.config.mathjax_options: options.update(app.config.mathjax_options) - builder.add_js_file(app.config.mathjax_path, **options) + app.add_js_file(app.config.mathjax_path, **options) # type: ignore if app.config.mathjax_config: body = "MathJax.Hub.Config(%s)" % json.dumps(app.config.mathjax_config) - builder.add_js_file(None, type="text/x-mathjax-config", body=body) + app.add_js_file(None, type="text/x-mathjax-config", body=body) def setup(app: Sphinx) -> Dict[str, Any]: @@ -93,15 +95,11 @@ def setup(app: Sphinx) -> Dict[str, Any]: (html_visit_math, None), (html_visit_displaymath, None)) - # more information for mathjax secure url is here: - # https://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn - app.add_config_value('mathjax_path', - 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?' - 'config=TeX-AMS-MML_HTMLorMML', 'html') + app.add_config_value('mathjax_path', MATHJAX_URL, 'html') app.add_config_value('mathjax_options', {}, 'html') app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html') app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html') app.add_config_value('mathjax_config', None, 'html') - app.connect('env-updated', install_mathjax) + app.connect('html-page-context', install_mathjax) return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index 9b41152fc..4a8c2135a 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -4,7 +4,7 @@ Support for NumPy and Google style docstrings. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,6 +13,7 @@ from typing import Any, Dict, List from sphinx import __display_version__ as __version__ from sphinx.application import Sphinx from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring +from sphinx.util import inspect class Config: @@ -40,7 +41,10 @@ class Config: napoleon_use_param = True napoleon_use_rtype = True napoleon_use_keyword = True + napoleon_preprocess_types = False + napoleon_type_aliases = None napoleon_custom_sections = None + napoleon_attr_annotations = True .. _Google style: https://google.github.io/styleguide/pyguide.html @@ -168,10 +172,11 @@ class Config: **If False**:: .. attribute:: attr1 - :type: int Description of `attr1` + :type: int + napoleon_use_param : :obj:`bool` (Defaults to True) True to use a ``:param:`` role for each function parameter. False to use a single ``:parameters:`` role for all the parameters. @@ -234,6 +239,13 @@ class Config: :returns: *bool* -- True if successful, False otherwise + napoleon_preprocess_types : :obj:`bool` (Defaults to False) + Enable the type preprocessor for numpy style docstrings. + + napoleon_type_aliases : :obj:`dict` (Defaults to None) + Add a mapping of strings to string, translating types in numpy + style docstrings. Only works if ``napoleon_preprocess_types = True``. + napoleon_custom_sections : :obj:`list` (Defaults to None) Add a list of custom sections to include, expanding the list of parsed sections. @@ -241,11 +253,19 @@ class Config: * To create a custom "generic" section, just pass a string. * To create an alias for an existing section, pass a tuple containing the alias name and the original, in that order. + * To create a custom section that displays like the parameters or returns + section, pass a tuple containing the custom section name and a string + value, "params_style" or "returns_style". If an entry is just a string, it is interpreted as a header for a generic section. If the entry is a tuple/list/indexed container, the first entry - is the name of the section, the second is the section key to emulate. + is the name of the section, the second is the section key to emulate. If the + second entry value is "params_style" or "returns_style", the custom section + will be displayed like the parameters section or returns section. + napoleon_attr_annotations : :obj:`bool` (Defaults to True) + Use the type annotations of class attributes that are documented in the docstring + but do not have a type in the docstring. """ _config_values = { @@ -261,7 +281,10 @@ class Config: 'napoleon_use_param': (True, 'env'), 'napoleon_use_rtype': (True, 'env'), 'napoleon_use_keyword': (True, 'env'), - 'napoleon_custom_sections': (None, 'env') + 'napoleon_preprocess_types': (False, 'env'), + 'napoleon_type_aliases': (None, 'env'), + 'napoleon_custom_sections': (None, 'env'), + 'napoleon_attr_annotations': (True, 'env'), } def __init__(self, **settings: Any) -> None: @@ -430,14 +453,14 @@ def _skip_member(app: Sphinx, what: str, name: str, obj: Any, if cls_path: try: if '.' in cls_path: - import importlib import functools + import importlib mod = importlib.import_module(obj.__module__) mod_path = cls_path.split('.') cls = functools.reduce(getattr, mod_path, mod) else: - cls = obj.__globals__[cls_path] + cls = inspect.unwrap(obj).__globals__[cls_path] except Exception: cls_is_owner = False else: diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index 32edd7f8f..bd1c44509 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -6,10 +6,11 @@ Classes for docstring parsing and formatting. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import collections import inspect import re from functools import partial @@ -18,26 +19,57 @@ from typing import Any, Callable, Dict, List, Tuple, Union from sphinx.application import Sphinx from sphinx.config import Config as SphinxConfig from sphinx.ext.napoleon.iterators import modify_iter -from sphinx.locale import _ +from sphinx.locale import _, __ +from sphinx.util import logging +from sphinx.util.inspect import stringify_annotation +from sphinx.util.typing import get_type_hints if False: # For type annotation from typing import Type # for python3.5.1 +logger = logging.getLogger(__name__) + _directive_regex = re.compile(r'\.\. \S+::') _google_section_regex = re.compile(r'^(\s|\w)+:\s*$') -_google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.*[^\s]+)\s*\)') +_google_typed_arg_regex = re.compile(r'(.+?)\(\s*(.*[^\s]+)\s*\)') _numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$') _single_colon_regex = re.compile(r'(?<!:):(?!:)') _xref_or_code_regex = re.compile( r'((?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)|' - r'(?:``.+``))') + r'(?:``.+?``))') +_xref_regex = re.compile( + r'(?:(?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:)?`.+?`)' +) _bullet_list_regex = re.compile(r'^(\*|\+|\-)(\s+\S|\s*$)') _enumerated_list_regex = re.compile( r'^(?P<paren>\()?' r'(\d+|#|[ivxlcdm]+|[IVXLCDM]+|[a-zA-Z])' r'(?(paren)\)|\.)(\s+\S|\s*$)') +_token_regex = re.compile( + r"(,\sor\s|\sor\s|\sof\s|:\s|\sto\s|,\sand\s|\sand\s|,\s" + r"|[{]|[}]" + r'|"(?:\\"|[^"])*"' + r"|'(?:\\'|[^'])*')" +) +_default_regex = re.compile( + r"^default[^_0-9A-Za-z].*$", +) +_SINGLETONS = ("None", "True", "False", "Ellipsis") + + +def _convert_type_spec(_type: str, translations: Dict[str, str] = {}) -> str: + """Convert type specification to reference in reST.""" + if _type in translations: + return translations[_type] + else: + if _type == 'None': + return ':obj:`None`' + else: + return ':class:`%s`' % _type + + return _type class GoogleDocstring: @@ -160,8 +192,11 @@ class GoogleDocstring: 'notes': self._parse_notes_section, 'other parameters': self._parse_other_parameters_section, 'parameters': self._parse_parameters_section, + 'receive': self._parse_receives_section, + 'receives': self._parse_receives_section, 'return': self._parse_returns_section, 'returns': self._parse_returns_section, + 'raise': self._parse_raises_section, 'raises': self._parse_raises_section, 'references': self._parse_references_section, 'see also': self._parse_see_also_section, @@ -169,6 +204,7 @@ class GoogleDocstring: 'todo': partial(self._parse_admonition, 'todo'), 'warning': partial(self._parse_admonition, 'warning'), 'warnings': partial(self._parse_admonition, 'warning'), + 'warn': self._parse_warns_section, 'warns': self._parse_warns_section, 'yield': self._parse_yields_section, 'yields': self._parse_yields_section, @@ -235,25 +271,32 @@ class GoogleDocstring: if parse_type: match = _google_typed_arg_regex.match(before) if match: - _name = match.group(1) + _name = match.group(1).strip() _type = match.group(2) _name = self._escape_args_and_kwargs(_name) if prefer_type and not _type: _type, _name = _name, _type + + if _type and self._config.napoleon_preprocess_types: + _type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {}) + indent = self._get_indent(line) + 1 _descs = [_desc] + self._dedent(self._consume_indented_block(indent)) _descs = self.__class__(_descs, self._config).lines() return _name, _type, _descs - def _consume_fields(self, parse_type: bool = True, prefer_type: bool = False - ) -> List[Tuple[str, str, List[str]]]: + def _consume_fields(self, parse_type: bool = True, prefer_type: bool = False, + multiple: bool = False) -> List[Tuple[str, str, List[str]]]: self._consume_empty() fields = [] while not self._is_section_break(): _name, _type, _desc = self._consume_field(parse_type, prefer_type) - if _name or _type or _desc: + if multiple and _name: + for name in _name.split(","): + fields.append((name.strip(), _type, _desc)) + elif _name or _type or _desc: fields.append((_name, _type, _desc,)) return fields @@ -267,7 +310,8 @@ class GoogleDocstring: _descs = self.__class__(_descs, self._config).lines() return _type, _descs - def _consume_returns_section(self) -> List[Tuple[str, str, List[str]]]: + def _consume_returns_section(self, preprocess_types: bool = False + ) -> List[Tuple[str, str, List[str]]]: lines = self._dedent(self._consume_to_next_section()) if lines: before, colon, after = self._partition_field_on_colon(lines[0]) @@ -281,6 +325,10 @@ class GoogleDocstring: _type = before + if (_type and preprocess_types and + self._config.napoleon_preprocess_types): + _type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {}) + _desc = self.__class__(_desc, self._config).lines() return [(_name, _type, _desc,)] else: @@ -523,11 +571,18 @@ class GoogleDocstring: self._sections[entry.lower()] = self._parse_custom_generic_section else: # otherwise, assume entry is container; - # [0] is new section, [1] is the section to alias. - # in the case of key mismatch, just handle as generic section. - self._sections[entry[0].lower()] = \ - self._sections.get(entry[1].lower(), - self._parse_custom_generic_section) + if entry[1] == "params_style": + self._sections[entry[0].lower()] = \ + self._parse_custom_params_style_section + elif entry[1] == "returns_style": + self._sections[entry[0].lower()] = \ + self._parse_custom_returns_style_section + else: + # [0] is new section, [1] is the section to alias. + # in the case of key mismatch, just handle as generic section. + self._sections[entry[0].lower()] = \ + self._sections.get(entry[1].lower(), + self._parse_custom_generic_section) def _parse(self) -> None: self._parsed_lines = self._consume_empty() @@ -578,6 +633,8 @@ class GoogleDocstring: def _parse_attributes_section(self, section: str) -> List[str]: lines = [] for _name, _type, _desc in self._consume_fields(): + if not _type: + _type = self._lookup_annotation(_name) if self._config.napoleon_use_ivar: _name = self._qualify_name(_name, self._obj) field = ':ivar %s: ' % _name @@ -588,12 +645,13 @@ class GoogleDocstring: lines.append('.. attribute:: ' + _name) if self._opt and 'noindex' in self._opt: lines.append(' :noindex:') - if _type: - lines.extend(self._indent([':type: %s' % _type], 3)) lines.append('') fields = self._format_field('', '', _desc) lines.extend(self._indent(fields, 3)) + if _type: + lines.append('') + lines.extend(self._indent([':type: %s' % _type], 3)) lines.append('') if self._config.napoleon_use_ivar: lines.append('') @@ -612,6 +670,13 @@ class GoogleDocstring: # for now, no admonition for simple custom sections return self._parse_generic_section(section, False) + def _parse_custom_params_style_section(self, section: str) -> List[str]: + return self._format_fields(section, self._consume_fields()) + + def _parse_custom_returns_style_section(self, section: str) -> List[str]: + fields = self._consume_returns_section(preprocess_types=True) + return self._format_fields(section, fields) + def _parse_usage_section(self, section: str) -> List[str]: header = ['.. rubric:: Usage:', ''] block = ['.. code-block:: python', ''] @@ -661,10 +726,12 @@ class GoogleDocstring: return self._format_fields(_('Other Parameters'), self._consume_fields()) def _parse_parameters_section(self, section: str) -> List[str]: - fields = self._consume_fields() if self._config.napoleon_use_param: + # Allow to declare multiple parameters at once (ex: x, y: int) + fields = self._consume_fields(multiple=True) return self._format_docutils_params(fields) else: + fields = self._consume_fields() return self._format_fields(_('Parameters'), fields) def _parse_raises_section(self, section: str) -> List[str]: @@ -674,6 +741,9 @@ class GoogleDocstring: m = self._name_rgx.match(_type) if m and m.group('name'): _type = m.group('name') + elif _xref_regex.match(_type): + pos = _type.find('`') + _type = _type[pos + 1:-1] _type = ' ' + _type if _type else '' _desc = self._strip_empty(_desc) _descs = ' ' + '\n '.join(_desc) if any(_desc) else '' @@ -682,6 +752,15 @@ class GoogleDocstring: lines.append('') return lines + def _parse_receives_section(self, section: str) -> List[str]: + if self._config.napoleon_use_param: + # Allow to declare multiple parameters at once (ex: x, y: int) + fields = self._consume_fields(multiple=True) + return self._format_docutils_params(fields) + else: + fields = self._consume_fields() + return self._format_fields(_('Receives'), fields) + def _parse_references_section(self, section: str) -> List[str]: use_admonition = self._config.napoleon_use_admonition_for_references return self._parse_generic_section(_('References'), use_admonition) @@ -721,7 +800,7 @@ class GoogleDocstring: return self._format_fields(_('Warns'), self._consume_fields()) def _parse_yields_section(self, section: str) -> List[str]: - fields = self._consume_returns_section() + fields = self._consume_returns_section(preprocess_types=True) return self._format_fields(_('Yields'), fields) def _partition_field_on_colon(self, line: str) -> Tuple[str, str, str]: @@ -776,6 +855,193 @@ class GoogleDocstring: lines = lines[start:end + 1] return lines + def _lookup_annotation(self, _name: str) -> str: + if self._config.napoleon_attr_annotations: + if self._what in ("module", "class", "exception") and self._obj: + # cache the class annotations + if not hasattr(self, "_annotations"): + localns = getattr(self._config, "autodoc_type_aliases", {}) + localns.update(getattr( + self._config, "napoleon_type_aliases", {} + ) or {}) + self._annotations = get_type_hints(self._obj, None, localns) + if _name in self._annotations: + return stringify_annotation(self._annotations[_name]) + # No annotation found + return "" + + +def _recombine_set_tokens(tokens: List[str]) -> List[str]: + token_queue = collections.deque(tokens) + keywords = ("optional", "default") + + def takewhile_set(tokens): + open_braces = 0 + previous_token = None + while True: + try: + token = tokens.popleft() + except IndexError: + break + + if token == ", ": + previous_token = token + continue + + if not token.strip(): + continue + + if token in keywords: + tokens.appendleft(token) + if previous_token is not None: + tokens.appendleft(previous_token) + break + + if previous_token is not None: + yield previous_token + previous_token = None + + if token == "{": + open_braces += 1 + elif token == "}": + open_braces -= 1 + + yield token + + if open_braces == 0: + break + + def combine_set(tokens): + while True: + try: + token = tokens.popleft() + except IndexError: + break + + if token == "{": + tokens.appendleft("{") + yield "".join(takewhile_set(tokens)) + else: + yield token + + return list(combine_set(token_queue)) + + +def _tokenize_type_spec(spec: str) -> List[str]: + def postprocess(item): + if _default_regex.match(item): + default = item[:7] + # can't be separated by anything other than a single space + # for now + other = item[8:] + + return [default, " ", other] + else: + return [item] + + tokens = list( + item + for raw_token in _token_regex.split(spec) + for item in postprocess(raw_token) + if item + ) + return tokens + + +def _token_type(token: str, location: str = None) -> str: + def is_numeric(token): + try: + # use complex to make sure every numeric value is detected as literal + complex(token) + except ValueError: + return False + else: + return True + + if token.startswith(" ") or token.endswith(" "): + type_ = "delimiter" + elif ( + is_numeric(token) or + (token.startswith("{") and token.endswith("}")) or + (token.startswith('"') and token.endswith('"')) or + (token.startswith("'") and token.endswith("'")) + ): + type_ = "literal" + elif token.startswith("{"): + logger.warning( + __("invalid value set (missing closing brace): %s"), + token, + location=location, + ) + type_ = "literal" + elif token.endswith("}"): + logger.warning( + __("invalid value set (missing opening brace): %s"), + token, + location=location, + ) + type_ = "literal" + elif token.startswith("'") or token.startswith('"'): + logger.warning( + __("malformed string literal (missing closing quote): %s"), + token, + location=location, + ) + type_ = "literal" + elif token.endswith("'") or token.endswith('"'): + logger.warning( + __("malformed string literal (missing opening quote): %s"), + token, + location=location, + ) + type_ = "literal" + elif token in ("optional", "default"): + # default is not a official keyword (yet) but supported by the + # reference implementation (numpydoc) and widely used + type_ = "control" + elif _xref_regex.match(token): + type_ = "reference" + else: + type_ = "obj" + + return type_ + + +def _convert_numpy_type_spec(_type: str, location: str = None, translations: dict = {}) -> str: + def convert_obj(obj, translations, default_translation): + translation = translations.get(obj, obj) + + # use :class: (the default) only if obj is not a standard singleton + if translation in _SINGLETONS and default_translation == ":class:`%s`": + default_translation = ":obj:`%s`" + elif translation == "..." and default_translation == ":class:`%s`": + # allow referencing the builtin ... + default_translation = ":obj:`%s <Ellipsis>`" + + if _xref_regex.match(translation) is None: + translation = default_translation % translation + + return translation + + tokens = _tokenize_type_spec(_type) + combined_tokens = _recombine_set_tokens(tokens) + types = [ + (token, _token_type(token, location)) + for token in combined_tokens + ] + + converters = { + "literal": lambda x: "``%s``" % x, + "obj": lambda x: convert_obj(x, translations, ":class:`%s`"), + "control": lambda x: "*%s*" % x, + "delimiter": lambda x: x, + "reference": lambda x: x, + } + + converted = "".join(converters.get(type_)(token) for token, type_ in types) + + return converted + class NumpyDocstring(GoogleDocstring): """Convert NumPy style docstrings to reStructuredText. @@ -876,6 +1142,28 @@ class NumpyDocstring(GoogleDocstring): self._directive_sections = ['.. index::'] super().__init__(docstring, config, app, what, name, obj, options) + def _get_location(self) -> str: + try: + filepath = inspect.getfile(self._obj) if self._obj is not None else None + except TypeError: + filepath = None + name = self._name + + if filepath is None and name is None: + return None + elif filepath is None: + filepath = "" + + return ":".join([filepath, "docstring of %s" % name]) + + def _escape_args_and_kwargs(self, name: str) -> str: + func = super()._escape_args_and_kwargs + + if ", " in name: + return ", ".join(func(param) for param in name.split(", ")) + else: + return func(name) + def _consume_field(self, parse_type: bool = True, prefer_type: bool = False ) -> Tuple[str, str, List[str]]: line = next(self._line_iter) @@ -886,14 +1174,26 @@ class NumpyDocstring(GoogleDocstring): _name, _type = _name.strip(), _type.strip() _name = self._escape_args_and_kwargs(_name) + if parse_type and not _type: + _type = self._lookup_annotation(_name) + if prefer_type and not _type: _type, _name = _name, _type + + if self._config.napoleon_preprocess_types: + _type = _convert_numpy_type_spec( + _type, + location=self._get_location(), + translations=self._config.napoleon_type_aliases or {}, + ) + indent = self._get_indent(line) + 1 _desc = self._dedent(self._consume_indented_block(indent)) _desc = self.__class__(_desc, self._config).lines() return _name, _type, _desc - def _consume_returns_section(self) -> List[Tuple[str, str, List[str]]]: + def _consume_returns_section(self, preprocess_types: bool = False + ) -> List[Tuple[str, str, List[str]]]: return self._consume_fields(prefer_type=True) def _consume_section_header(self) -> str: @@ -963,6 +1263,22 @@ class NumpyDocstring(GoogleDocstring): items.append((name, list(rest), role)) del rest[:] + def translate(func, description, role): + translations = self._config.napoleon_type_aliases + if role is not None or not translations: + return func, description, role + + translated = translations.get(func, func) + match = self._name_rgx.match(translated) + if not match: + return translated, description, role + + groups = match.groupdict() + role = groups["role"] + new_func = groups["name"] or groups["name2"] + + return new_func, description, role + current_func = None rest = [] # type: List[str] @@ -993,37 +1309,19 @@ class NumpyDocstring(GoogleDocstring): if not items: return [] - roles = { - 'method': 'meth', - 'meth': 'meth', - 'function': 'func', - 'func': 'func', - 'class': 'class', - 'exception': 'exc', - 'exc': 'exc', - 'object': 'obj', - 'obj': 'obj', - 'module': 'mod', - 'mod': 'mod', - 'data': 'data', - 'constant': 'const', - 'const': 'const', - 'attribute': 'attr', - 'attr': 'attr' - } - if self._what is None: - func_role = 'obj' - else: - func_role = roles.get(self._what, '') + # apply type aliases + items = [ + translate(func, description, role) + for func, description, role in items + ] + lines = [] # type: List[str] last_had_desc = True - for func, desc, role in items: + for name, desc, role in items: if role: - link = ':%s:`%s`' % (role, func) - elif func_role: - link = ':%s:`%s`' % (func_role, func) + link = ':%s:`%s`' % (role, name) else: - link = "`%s`_" % func + link = ':obj:`%s`' % name if desc or last_had_desc: lines += [''] lines += [link] diff --git a/sphinx/ext/napoleon/iterators.py b/sphinx/ext/napoleon/iterators.py index fc41afdb3..e0f5cca9c 100644 --- a/sphinx/ext/napoleon/iterators.py +++ b/sphinx/ext/napoleon/iterators.py @@ -6,7 +6,7 @@ A collection of helpful iterators. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index bfb46903f..640c93935 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -7,13 +7,12 @@ all todos of your project and lists them along with a backlink to the original location. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import warnings -from typing import Any, Dict, Iterable, List, Tuple -from typing import cast +from typing import Any, Dict, Iterable, List, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index a2eeb7891..baf86dbbf 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -4,12 +4,15 @@ Add links to module code in Python object descriptions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import posixpath import traceback -from typing import Any, Dict, Iterable, Iterator, Set, Tuple +import warnings +from os import path +from typing import Any, Dict, Generator, Iterable, Optional, Set, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node @@ -17,17 +20,32 @@ from docutils.nodes import Element, Node import sphinx from sphinx import addnodes from sphinx.application import Sphinx +from sphinx.builders import Builder +from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.deprecation import RemovedInSphinx50Warning from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer +from sphinx.transforms.post_transforms import SphinxPostTransform from sphinx.util import get_full_modname, logging, status_iterator from sphinx.util.nodes import make_refnode - logger = logging.getLogger(__name__) -def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> str: +OUTPUT_DIRNAME = '_modules' + + +class viewcode_anchor(Element): + """Node for viewcode anchors. + + This node will be processed in the resolving phase. + For viewcode supported builders, they will be all converted to the anchors. + For not supported builders, they will be removed. + """ + + +def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> Optional[str]: try: return get_full_modname(modname, attribute) except AttributeError: @@ -45,14 +63,21 @@ def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> str: return None +def is_supported_builder(builder: Builder) -> bool: + if builder.format != 'html': + return False + elif builder.name == 'singlehtml': + return False + elif builder.name.startswith('epub') and not builder.config.viewcode_enable_epub: + return False + else: + return True + + def doctree_read(app: Sphinx, doctree: Node) -> None: env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # type: ignore - if app.builder.name == "singlehtml": - return - if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub: - return def has_tag(modname: str, fullname: str, docname: str, refname: str) -> bool: entry = env._viewcode_modules.get(modname, None) # type: ignore @@ -109,13 +134,8 @@ def doctree_read(app: Sphinx, doctree: Node) -> None: # only one link per name, please continue names.add(fullname) - pagename = '_modules/' + modname.replace('.', '/') - inline = nodes.inline('', _('[source]'), classes=['viewcode-link']) - onlynode = addnodes.only(expr='html') - onlynode += addnodes.pending_xref('', inline, reftype='viewcode', refdomain='std', - refexplicit=False, reftarget=pagename, - refid=fullname, refdoc=env.docname) - signode += onlynode + pagename = posixpath.join(OUTPUT_DIRNAME, modname.replace('.', '/')) + signode += viewcode_anchor(reftarget=pagename, refid=fullname, refdoc=env.docname) def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], @@ -129,22 +149,80 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], env._viewcode_modules.update(other._viewcode_modules) # type: ignore +class ViewcodeAnchorTransform(SphinxPostTransform): + """Convert or remove viewcode_anchor nodes depends on builder.""" + default_priority = 100 + + def run(self, **kwargs: Any) -> None: + if is_supported_builder(self.app.builder): + self.convert_viewcode_anchors() + else: + self.remove_viewcode_anchors() + + def convert_viewcode_anchors(self) -> None: + for node in self.document.traverse(viewcode_anchor): + anchor = nodes.inline('', _('[source]'), classes=['viewcode-link']) + refnode = make_refnode(self.app.builder, node['refdoc'], node['reftarget'], + node['refid'], anchor) + node.replace_self(refnode) + + def remove_viewcode_anchors(self) -> None: + for node in self.document.traverse(viewcode_anchor): + node.parent.remove(node) + + def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: Node - ) -> Node: - if app.builder.format != 'html': - return None - elif node['reftype'] == 'viewcode': - # resolve our "viewcode" reference nodes -- they need special treatment + ) -> Optional[Node]: + # resolve our "viewcode" reference nodes -- they need special treatment + if node['reftype'] == 'viewcode': + warnings.warn('viewcode extension is no longer use pending_xref node. ' + 'Please update your extension.', RemovedInSphinx50Warning) return make_refnode(app.builder, node['refdoc'], node['reftarget'], node['refid'], contnode) return None -def collect_pages(app: Sphinx) -> Iterator[Tuple[str, Dict[str, Any], str]]: +def get_module_filename(app: Sphinx, modname: str) -> Optional[str]: + """Get module filename for *modname*.""" + source_info = app.emit_firstresult('viewcode-find-source', modname) + if source_info: + return None + else: + try: + filename, source = ModuleAnalyzer.get_module_source(modname) + return filename + except Exception: + return None + + +def should_generate_module_page(app: Sphinx, modname: str) -> bool: + """Check generation of module page is needed.""" + module_filename = get_module_filename(app, modname) + if module_filename is None: + # Always (re-)generate module page when module filename is not found. + return True + + builder = cast(StandaloneHTMLBuilder, app.builder) + basename = modname.replace('.', '/') + builder.out_suffix + page_filename = path.join(app.outdir, '_modules/', basename) + + try: + if path.getmtime(module_filename) <= path.getmtime(page_filename): + # generation is not needed if the HTML page is newer than module file. + return False + except IOError: + pass + + return True + + +def collect_pages(app: Sphinx) -> Generator[Tuple[str, Dict[str, Any], str], None, None]: env = app.builder.env if not hasattr(env, '_viewcode_modules'): return + if not is_supported_builder(app.builder): + return highlighter = app.builder.highlighter # type: ignore urito = app.builder.get_relative_uri @@ -157,9 +235,12 @@ def collect_pages(app: Sphinx) -> Iterator[Tuple[str, Dict[str, Any], str]]: app.verbosity, lambda x: x[0]): if not entry: continue + if not should_generate_module_page(app, modname): + continue + code, tags, used, refname = entry # construct a page name for the highlighted source - pagename = '_modules/' + modname.replace('.', '/') + pagename = posixpath.join(OUTPUT_DIRNAME, modname.replace('.', '/')) # highlight the source using the builder's highlighter if env.config.highlight_language in ('python3', 'default', 'none'): lexer = env.config.highlight_language @@ -191,10 +272,10 @@ def collect_pages(app: Sphinx) -> Iterator[Tuple[str, Dict[str, Any], str]]: parent = parent.rsplit('.', 1)[0] if parent in modnames: parents.append({ - 'link': urito(pagename, '_modules/' + - parent.replace('.', '/')), + 'link': urito(pagename, + posixpath.join(OUTPUT_DIRNAME, parent.replace('.', '/'))), 'title': parent}) - parents.append({'link': urito(pagename, '_modules/index'), + parents.append({'link': urito(pagename, posixpath.join(OUTPUT_DIRNAME, 'index')), 'title': _('Module code')}) parents.reverse() # putting it all together @@ -223,7 +304,8 @@ def collect_pages(app: Sphinx) -> Iterator[Tuple[str, Dict[str, Any], str]]: html.append('</ul>') stack.append(modname + '.') html.append('<li><a href="%s">%s</a></li>\n' % ( - urito('_modules/index', '_modules/' + modname.replace('.', '/')), + urito(posixpath.join(OUTPUT_DIRNAME, 'index'), + posixpath.join(OUTPUT_DIRNAME, modname.replace('.', '/'))), modname)) html.append('</ul>' * (len(stack) - 1)) context = { @@ -232,7 +314,7 @@ def collect_pages(app: Sphinx) -> Iterator[Tuple[str, Dict[str, Any], str]]: ''.join(html)), } - yield ('_modules/index', context, 'page.html') + yield (posixpath.join(OUTPUT_DIRNAME, 'index'), context, 'page.html') def setup(app: Sphinx) -> Dict[str, Any]: @@ -247,6 +329,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: # app.add_config_value('viewcode_exclude_modules', [], 'env') app.add_event('viewcode-find-source') app.add_event('viewcode-follow-imported') + app.add_post_transform(ViewcodeAnchorTransform) return { 'version': sphinx.__display_version__, 'env_version': 1, diff --git a/sphinx/extension.py b/sphinx/extension.py index fa7a0d490..8129d89af 100644 --- a/sphinx/extension.py +++ b/sphinx/extension.py @@ -4,7 +4,7 @@ Utilities for Sphinx extensions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index 4dc9ce543..8425009f7 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -4,7 +4,7 @@ Highlight code blocks using Pygments. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -17,18 +17,16 @@ from pygments.filters import ErrorToken from pygments.formatter import Formatter from pygments.formatters import HtmlFormatter, LatexFormatter from pygments.lexer import Lexer -from pygments.lexers import get_lexer_by_name, guess_lexer -from pygments.lexers import PythonLexer, Python3Lexer, PythonConsoleLexer, \ - CLexer, TextLexer, RstLexer +from pygments.lexers import (CLexer, Python3Lexer, PythonConsoleLexer, PythonLexer, RstLexer, + TextLexer, get_lexer_by_name, guess_lexer) from pygments.style import Style from pygments.styles import get_style_by_name from pygments.util import ClassNotFound from sphinx.locale import __ -from sphinx.pygments_styles import SphinxStyle, NoneStyle +from sphinx.pygments_styles import NoneStyle, SphinxStyle from sphinx.util import logging, texescape - logger = logging.getLogger(__name__) lexers = {} # type: Dict[str, Lexer] diff --git a/sphinx/io.py b/sphinx/io.py index f45d5bf5d..3508dd58d 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -4,7 +4,7 @@ Input/Output files - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import codecs @@ -22,24 +22,23 @@ from docutils.transforms import Transform from docutils.transforms.references import DanglingReferences from docutils.writers import UnfilteredWriter +from sphinx import addnodes from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.environment import BuildEnvironment from sphinx.errors import FiletypeNotFoundError -from sphinx.transforms import ( - AutoIndexUpgrader, DoctreeReadEvent, FigureAligner, SphinxTransformer -) -from sphinx.transforms.i18n import ( - PreserveTranslatableMessages, Locale, RemoveTranslatableInline, -) +from sphinx.transforms import (AutoIndexUpgrader, DoctreeReadEvent, FigureAligner, + SphinxTransformer) +from sphinx.transforms.i18n import (Locale, PreserveTranslatableMessages, + RemoveTranslatableInline) from sphinx.transforms.references import SphinxDomains -from sphinx.util import logging, get_filetype -from sphinx.util import UnicodeDecodeErrorHandler +from sphinx.util import UnicodeDecodeErrorHandler, get_filetype, logging from sphinx.util.docutils import LoggingReporter from sphinx.versioning import UIDTransform if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx @@ -96,6 +95,7 @@ class SphinxBaseReader(standalone.Reader): for logging. """ document = super().new_document() + document.__class__ = addnodes.document # replace the class with patched version # substitute transformer document.transformer = SphinxTransformer(document) @@ -227,4 +227,8 @@ deprecated_alias('sphinx.io', 'FiletypeNotFoundError': FiletypeNotFoundError, 'get_filetype': get_filetype, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'FiletypeNotFoundError': 'sphinx.errors.FiletypeNotFoundError', + 'get_filetype': 'sphinx.util.get_filetype', + }) diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py index e943cfb1e..c890455f3 100644 --- a/sphinx/jinja2glue.py +++ b/sphinx/jinja2glue.py @@ -4,7 +4,7 @@ Glue code for the jinja2 templating engine. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,7 +12,7 @@ from os import path from pprint import pformat from typing import Any, Callable, Dict, Iterator, List, Tuple, Union -from jinja2 import FileSystemLoader, BaseLoader, TemplateNotFound, contextfunction +from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound, contextfunction from jinja2.environment import Environment from jinja2.sandbox import SandboxedEnvironment from jinja2.utils import open_if_exists @@ -186,7 +186,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader): self.environment.globals['accesskey'] = contextfunction(accesskey) self.environment.globals['idgen'] = idgen if use_i18n: - self.environment.install_gettext_translations(builder.app.translator) # type: ignore # NOQA + self.environment.install_gettext_translations(builder.app.translator) def render(self, template: str, context: Dict) -> str: # type: ignore return self.environment.get_template(template).render(context) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 385ca3566..bedd9e1cb 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -4,7 +4,7 @@ Locale utilities. - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -106,7 +106,7 @@ class _TranslationProxy(UserString): translators = defaultdict(NullTranslations) # type: Dict[Tuple[str, str], NullTranslations] -def init(locale_dirs: List[str], language: str, +def init(locale_dirs: List[Optional[str]], language: str, catalog: str = 'sphinx', namespace: str = 'general') -> Tuple[NullTranslations, bool]: """Look for message catalogs in `locale_dirs` and *ensure* that there is at least a NullTranslations catalog set in `translators`. If called multiple diff --git a/sphinx/locale/ar/LC_MESSAGES/sphinx.js b/sphinx/locale/ar/LC_MESSAGES/sphinx.js index 0c54e3398..d1dfdd3a1 100644 --- a/sphinx/locale/ar/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ar/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ar", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\"> \u062d\u0642\u0648\u0642 \u0627\u0644\u0646\u0634\u0631 </a> %(copyright)s", "© Copyright %(copyright)s.": "© \u062d\u0642\u0648\u0642 \u0627\u0644\u0646\u0634\u0631 %(copyright)s", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "\u0627\u0644\u0645\u0648\u0636\u0648\u0639 \u0627\u0644\u062a\u0627\u0644\u064a", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "\u0627\u0644\u0645\u0648\u0636\u0648\u0639 \u0627\u0644\u0633\u0627\u0628\u0642", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "\u0627\u0644\u0628\u062d\u062b \u0636\u0645\u0646 %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "\u0627\u0644\u0641\u0635\u0644 \u0627\u0644\u062a\u0627\u0644\u064a", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ar", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\"> \u062d\u0642\u0648\u0642 \u0627\u0644\u0646\u0634\u0631 </a> %(copyright)s", + "© Copyright %(copyright)s.": "© \u062d\u0642\u0648\u0642 \u0627\u0644\u0646\u0634\u0631 %(copyright)s", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "\u0627\u0644\u0645\u0648\u0636\u0648\u0639 \u0627\u0644\u062a\u0627\u0644\u064a", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "\u0627\u0644\u0645\u0648\u0636\u0648\u0639 \u0627\u0644\u0633\u0627\u0628\u0642", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "\u0627\u0644\u0628\u062d\u062b \u0636\u0645\u0646 %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "\u0627\u0644\u0641\u0635\u0644 \u0627\u0644\u062a\u0627\u0644\u064a", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5" +});
\ No newline at end of file diff --git a/sphinx/locale/ar/LC_MESSAGES/sphinx.po b/sphinx/locale/ar/LC_MESSAGES/sphinx.po index bd69d2aeb..371395b7b 100644 --- a/sphinx/locale/ar/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ar/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Mohammed Shannaq <sam@ms.per.jo>, 2018 msgid "" diff --git a/sphinx/locale/bg/LC_MESSAGES/sphinx.js b/sphinx/locale/bg/LC_MESSAGES/sphinx.js index 5b0f95dd3..2b1ce4750 100644 --- a/sphinx/locale/bg/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/bg/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "bg", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "bg", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/bg/LC_MESSAGES/sphinx.po b/sphinx/locale/bg/LC_MESSAGES/sphinx.po index 79329a57a..6d36b05f3 100644 --- a/sphinx/locale/bg/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/bg/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/bn/LC_MESSAGES/sphinx.js b/sphinx/locale/bn/LC_MESSAGES/sphinx.js index 3a4d190e1..599fc072e 100644 --- a/sphinx/locale/bn/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/bn/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "bn", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "\u098f\u0987 \u09a1\u0995\u09c1\u09ae\u09c7\u09a8\u09cd\u099f \u09b8\u09ae\u09cd\u09aa\u09b0\u09cd\u0995\u09c7", "Automatically generated list of changes in version %(version)s": "\u09b8\u09cd\u09ac\u09df\u0982\u0995\u09cd\u09b0\u09bf\u09df\u09ad\u09be\u09ac\u09c7 \u09a4\u09c8\u09b0\u09c0 %(version)s-\u098f \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u09b8\u09ae\u09c2\u09b9\u09c7\u09b0 \u09a4\u09be\u09b2\u09bf\u0995\u09be\u0964", "C API changes": "C API \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "\u09aa\u09c2\u09b0\u09cd\u09a3\u09be\u0999\u09cd\u0997 \u09b8\u09c2\u099a\u09c0\u09aa\u09a4\u09cd\u09b0", "Contents": "", "Copyright": "\u0995\u09aa\u09bf\u09b0\u09be\u0987\u099f", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u09a6\u09bf\u09df\u09c7 \u09a4\u09c8\u09b0\u09c0\u0964", "Expand sidebar": "", "Full index on one page": "\u098f\u0995 \u09aa\u09be\u09a4\u09be\u09df \u09b8\u09ae\u09cd\u09aa\u09c2\u09b0\u09cd\u09a3 \u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8", "General Index": "\u09b8\u09be\u09a7\u09be\u09b0\u09a3 \u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8", "Global Module Index": "\u0997\u09cd\u09b2\u09c7\u09be\u09ac\u09be\u09b2 \u09ae\u09a1\u09bf\u0989\u09b2 \u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8", "Go": "\u09af\u09be\u09a8", "Hide Search Matches": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7\u09b0 \u09ae\u09cd\u09af\u09be\u099a\u0997\u09c1\u09b2\u09c7\u09be \u09b2\u09c1\u0995\u09be\u09a8", "Index": "\u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8", "Index – %(key)s": "\u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8 – %(key)s", "Index pages by letter": "\u09ac\u09b0\u09cd\u09a3\u09be\u09a8\u09c1\u09b8\u09be\u09b0\u09c7 \u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8 \u09aa\u09be\u09a4\u09be", "Indices and tables:": "\u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8 \u0993 \u099f\u09c7\u09ac\u09bf\u09b2 \u09b8\u09ae\u09c2\u09b9:", "Last updated on %(last_updated)s.": "%(last_updated)s \u09b8\u09b0\u09cd\u09ac\u09b6\u09c7\u09b7 \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u0995\u09b0\u09be \u09b9\u09df\u09c7\u099b\u09c7\u0964", "Library changes": "\u09b2\u09be\u0987\u09ac\u09cd\u09b0\u09c7\u09b0\u09bf\u09b0 \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8", "Navigation": "\u09a8\u09c7\u09ad\u09bf\u0997\u09c7\u09b6\u09a8", "Next topic": "\u09aa\u09b0\u09ac\u09b0\u09cd\u09a4\u09c0 \u099f\u09aa\u09bf\u0995", "Other changes": "\u0985\u09a8\u09cd\u09af\u09be\u09a8\u09cd\u09af \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8", "Overview": "\u09ad\u09c1\u09ae\u09bf\u0995\u09be", "Permalink to this definition": "\u098f\u0987 \u09b8\u0982\u099c\u09cd\u099e\u09be\u09b0 \u09aa\u09be\u09b0\u09cd\u09ae\u09be\u09b2\u09bf\u0999\u09cd\u0995", "Permalink to this headline": "\u098f\u0987 \u09b6\u09bf\u09b0\u09c7\u09be\u09a8\u09be\u09ae\u09c7\u09b0 \u09aa\u09be\u09b0\u09cd\u09ae\u09be\u09b2\u09bf\u0999\u09cd\u0995", "Please activate JavaScript to enable the search\n functionality.": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8 \u0995\u09b0\u09be\u09b0 \u099c\u09a8\u09cd\u09af \u0985\u09a8\u09c1\u0997\u09cd\u09b0\u09b9\u09aa\u09c2\u09b0\u09cd\u09ac\u0995 \u099c\u09be\u09ad\u09be\u09b8\u09cd\u0995\u09cd\u09b0\u09bf\u09aa\u09cd\u099f \n \u09b8\u0995\u09cd\u09b0\u09bf\u09df \u0995\u09b0\u09c1\u09a8\u0964", "Preparing search...": "", "Previous topic": "\u09aa\u09c2\u09b0\u09cd\u09ac\u09ac\u09b0\u09cd\u09a4\u09c0 \u099f\u09aa\u09bf\u0995", "Quick search": "\u09a6\u09cd\u09b0\u09c1\u09a4 \u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8", "Search": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8", "Search Page": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8 \u09aa\u09be\u09a4\u09be", "Search Results": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7\u09b0 \u09ab\u09b2\u09be\u09ab\u09b2", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "%(docstitle)s \u098f\u09b0 \u09ae\u09a7\u09cd\u09af\u09c7 \u0996\u09c1\u0981\u099c\u09c1\u09a8", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u09b8\u09c7\u09be\u09b0\u09cd\u09b8 \u09a6\u09c7\u0996\u09c1\u09a8", "Table of Contents": "", "This Page": "\u098f\u0987 \u09aa\u09be\u09a4\u09be", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "\u09b8\u0995\u09b2 \u09ab\u09be\u0982\u09b6\u09a8, \u0995\u09cd\u09b2\u09be\u09b8, \u099f\u09be\u09b0\u09cd\u09ae", "can be huge": "\u0996\u09c1\u09ac \u09ac\u09dc \u09b9\u09a4\u09c7 \u09aa\u09be\u09b0\u09c7", "last updated": "", "lists all sections and subsections": "\u09b8\u0995\u09b2 \u0985\u09a8\u09c1\u099a\u09cd\u099b\u09c7\u09a6 \u09b8\u09ae\u09c2\u09b9\u09c7\u09b0 \u09a4\u09be\u09b2\u09bf\u0995\u09be", "next chapter": "\u09aa\u09b0\u09ac\u09b0\u09cd\u09a4\u09c0 \u0985\u09a7\u09cd\u09af\u09be\u09df", "previous chapter": "\u09aa\u09c2\u09b0\u09cd\u09ac\u09ac\u09b0\u09cd\u09a4\u09c0 \u0985\u09a7\u09cd\u09af\u09be\u09df", "quick access to all modules": "\u09b8\u0995\u09b2 \u09ae\u09a1\u09bf\u0989\u09b2\u09c7 \u09a6\u09cd\u09b0\u09c1\u09a4 \u09aa\u09cd\u09b0\u09ac\u09c7\u09b6", "search": "\u0996\u09c1\u0981\u099c\u09c1\u09a8", "search this documentation": "\u098f\u0987 \u09b8\u09b9\u09be\u09df\u09bf\u0995\u09be\u09a4\u09c7 \u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be \u0995\u09b0\u09c1\u09a8", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "bn", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "\u098f\u0987 \u09a1\u0995\u09c1\u09ae\u09c7\u09a8\u09cd\u099f \u09b8\u09ae\u09cd\u09aa\u09b0\u09cd\u0995\u09c7", + "Automatically generated list of changes in version %(version)s": "\u09b8\u09cd\u09ac\u09df\u0982\u0995\u09cd\u09b0\u09bf\u09df\u09ad\u09be\u09ac\u09c7 \u09a4\u09c8\u09b0\u09c0 %(version)s-\u098f \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u09b8\u09ae\u09c2\u09b9\u09c7\u09b0 \u09a4\u09be\u09b2\u09bf\u0995\u09be\u0964", + "C API changes": "C API \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "\u09aa\u09c2\u09b0\u09cd\u09a3\u09be\u0999\u09cd\u0997 \u09b8\u09c2\u099a\u09c0\u09aa\u09a4\u09cd\u09b0", + "Contents": "", + "Copyright": "\u0995\u09aa\u09bf\u09b0\u09be\u0987\u099f", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u09a6\u09bf\u09df\u09c7 \u09a4\u09c8\u09b0\u09c0\u0964", + "Expand sidebar": "", + "Full index on one page": "\u098f\u0995 \u09aa\u09be\u09a4\u09be\u09df \u09b8\u09ae\u09cd\u09aa\u09c2\u09b0\u09cd\u09a3 \u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8", + "General Index": "\u09b8\u09be\u09a7\u09be\u09b0\u09a3 \u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8", + "Global Module Index": "\u0997\u09cd\u09b2\u09c7\u09be\u09ac\u09be\u09b2 \u09ae\u09a1\u09bf\u0989\u09b2 \u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8", + "Go": "\u09af\u09be\u09a8", + "Hide Search Matches": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7\u09b0 \u09ae\u09cd\u09af\u09be\u099a\u0997\u09c1\u09b2\u09c7\u09be \u09b2\u09c1\u0995\u09be\u09a8", + "Index": "\u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8", + "Index – %(key)s": "\u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8 – %(key)s", + "Index pages by letter": "\u09ac\u09b0\u09cd\u09a3\u09be\u09a8\u09c1\u09b8\u09be\u09b0\u09c7 \u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8 \u09aa\u09be\u09a4\u09be", + "Indices and tables:": "\u0987\u09a8\u09a1\u09c7\u0995\u09cd\u09b8 \u0993 \u099f\u09c7\u09ac\u09bf\u09b2 \u09b8\u09ae\u09c2\u09b9:", + "Last updated on %(last_updated)s.": "%(last_updated)s \u09b8\u09b0\u09cd\u09ac\u09b6\u09c7\u09b7 \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u0995\u09b0\u09be \u09b9\u09df\u09c7\u099b\u09c7\u0964", + "Library changes": "\u09b2\u09be\u0987\u09ac\u09cd\u09b0\u09c7\u09b0\u09bf\u09b0 \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8", + "Navigation": "\u09a8\u09c7\u09ad\u09bf\u0997\u09c7\u09b6\u09a8", + "Next topic": "\u09aa\u09b0\u09ac\u09b0\u09cd\u09a4\u09c0 \u099f\u09aa\u09bf\u0995", + "Other changes": "\u0985\u09a8\u09cd\u09af\u09be\u09a8\u09cd\u09af \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8", + "Overview": "\u09ad\u09c1\u09ae\u09bf\u0995\u09be", + "Permalink to this definition": "\u098f\u0987 \u09b8\u0982\u099c\u09cd\u099e\u09be\u09b0 \u09aa\u09be\u09b0\u09cd\u09ae\u09be\u09b2\u09bf\u0999\u09cd\u0995", + "Permalink to this headline": "\u098f\u0987 \u09b6\u09bf\u09b0\u09c7\u09be\u09a8\u09be\u09ae\u09c7\u09b0 \u09aa\u09be\u09b0\u09cd\u09ae\u09be\u09b2\u09bf\u0999\u09cd\u0995", + "Please activate JavaScript to enable the search\n functionality.": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8 \u0995\u09b0\u09be\u09b0 \u099c\u09a8\u09cd\u09af \u0985\u09a8\u09c1\u0997\u09cd\u09b0\u09b9\u09aa\u09c2\u09b0\u09cd\u09ac\u0995 \u099c\u09be\u09ad\u09be\u09b8\u09cd\u0995\u09cd\u09b0\u09bf\u09aa\u09cd\u099f \n \u09b8\u0995\u09cd\u09b0\u09bf\u09df \u0995\u09b0\u09c1\u09a8\u0964", + "Preparing search...": "", + "Previous topic": "\u09aa\u09c2\u09b0\u09cd\u09ac\u09ac\u09b0\u09cd\u09a4\u09c0 \u099f\u09aa\u09bf\u0995", + "Quick search": "\u09a6\u09cd\u09b0\u09c1\u09a4 \u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8", + "Search": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8", + "Search Page": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8 \u09aa\u09be\u09a4\u09be", + "Search Results": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7\u09b0 \u09ab\u09b2\u09be\u09ab\u09b2", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "%(docstitle)s \u098f\u09b0 \u09ae\u09a7\u09cd\u09af\u09c7 \u0996\u09c1\u0981\u099c\u09c1\u09a8", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u09b8\u09c7\u09be\u09b0\u09cd\u09b8 \u09a6\u09c7\u0996\u09c1\u09a8", + "Table of Contents": "", + "This Page": "\u098f\u0987 \u09aa\u09be\u09a4\u09be", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "\u09b8\u0995\u09b2 \u09ab\u09be\u0982\u09b6\u09a8, \u0995\u09cd\u09b2\u09be\u09b8, \u099f\u09be\u09b0\u09cd\u09ae", + "can be huge": "\u0996\u09c1\u09ac \u09ac\u09dc \u09b9\u09a4\u09c7 \u09aa\u09be\u09b0\u09c7", + "last updated": "", + "lists all sections and subsections": "\u09b8\u0995\u09b2 \u0985\u09a8\u09c1\u099a\u09cd\u099b\u09c7\u09a6 \u09b8\u09ae\u09c2\u09b9\u09c7\u09b0 \u09a4\u09be\u09b2\u09bf\u0995\u09be", + "next chapter": "\u09aa\u09b0\u09ac\u09b0\u09cd\u09a4\u09c0 \u0985\u09a7\u09cd\u09af\u09be\u09df", + "previous chapter": "\u09aa\u09c2\u09b0\u09cd\u09ac\u09ac\u09b0\u09cd\u09a4\u09c0 \u0985\u09a7\u09cd\u09af\u09be\u09df", + "quick access to all modules": "\u09b8\u0995\u09b2 \u09ae\u09a1\u09bf\u0989\u09b2\u09c7 \u09a6\u09cd\u09b0\u09c1\u09a4 \u09aa\u09cd\u09b0\u09ac\u09c7\u09b6", + "search": "\u0996\u09c1\u0981\u099c\u09c1\u09a8", + "search this documentation": "\u098f\u0987 \u09b8\u09b9\u09be\u09df\u09bf\u0995\u09be\u09a4\u09c7 \u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be \u0995\u09b0\u09c1\u09a8", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/bn/LC_MESSAGES/sphinx.po b/sphinx/locale/bn/LC_MESSAGES/sphinx.po index 63aae6877..98ecbe5d0 100644 --- a/sphinx/locale/bn/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/bn/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2009 msgid "" diff --git a/sphinx/locale/ca/LC_MESSAGES/sphinx.js b/sphinx/locale/ca/LC_MESSAGES/sphinx.js index cfb2998f1..35a589ad4 100644 --- a/sphinx/locale/ca/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ca/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ca", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "Quant a aquests documents", "Automatically generated list of changes in version %(version)s": "Llista de canvis de la versi\u00f3 %(version)s generada autom\u00e0ticament", "C API changes": "Canvis a la API de C", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "Taula de Contingut Completa", "Contents": "", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Creat amb <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "", "Full index on one page": "\u00cdndex complet en una p\u00e0gina", "General Index": "\u00cdndex General", "Global Module Index": "\u00cdndex Global de M\u00f2duls", "Go": "Ves a", "Hide Search Matches": "Oculta Resultats de Cerca", "Index": "\u00cdndex", "Index – %(key)s": "\u00cdndes – %(key)s", "Index pages by letter": "P\u00e0gines d'\u00edndex per lletra", "Indices and tables:": "\u00cdndexs i taules:", "Last updated on %(last_updated)s.": "\u00daltima actualitzaci\u00f3 el %(last_updated)s.", "Library changes": "Canvis a la llibreria", "Navigation": "Navegaci\u00f3", "Next topic": "Tema seg\u00fcent", "Other changes": "Altres canvis", "Overview": "Resum", "Permalink to this definition": "Link permanent a aquesta definici\u00f3", "Permalink to this headline": "Link permanent a aquest t\u00edtol", "Please activate JavaScript to enable the search\n functionality.": "Activa JavaScript per utilitzar la funcionalitat\nde cerca.", "Preparing search...": "", "Previous topic": "Tema anterior", "Quick search": "Cerca r\u00e0pida", "Search": "Cerca", "Search Page": "P\u00e0gina de Cerca", "Search Results": "Resultats de la Cerca", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "Cerca dins de %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Mostra Codi Font", "Table of Contents": "", "This Page": "Aquesta P\u00e0gina", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "totes les funcions, classes, termes", "can be huge": "pot ser gegant", "last updated": "", "lists all sections and subsections": "llista totes les seccions i subseccions", "next chapter": "cap\u00edtol seg\u00fcent", "previous chapter": "cap\u00edtol anterior", "quick access to all modules": "acc\u00e9s r\u00e0pid a tots els m\u00f2duls", "search": "cerca", "search this documentation": "cerca aquesta documentaci\u00f3", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ca", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "Quant a aquests documents", + "Automatically generated list of changes in version %(version)s": "Llista de canvis de la versi\u00f3 %(version)s generada autom\u00e0ticament", + "C API changes": "Canvis a la API de C", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "Taula de Contingut Completa", + "Contents": "", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Creat amb <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "", + "Full index on one page": "\u00cdndex complet en una p\u00e0gina", + "General Index": "\u00cdndex General", + "Global Module Index": "\u00cdndex Global de M\u00f2duls", + "Go": "Ves a", + "Hide Search Matches": "Oculta Resultats de Cerca", + "Index": "\u00cdndex", + "Index – %(key)s": "\u00cdndes – %(key)s", + "Index pages by letter": "P\u00e0gines d'\u00edndex per lletra", + "Indices and tables:": "\u00cdndexs i taules:", + "Last updated on %(last_updated)s.": "\u00daltima actualitzaci\u00f3 el %(last_updated)s.", + "Library changes": "Canvis a la llibreria", + "Navigation": "Navegaci\u00f3", + "Next topic": "Tema seg\u00fcent", + "Other changes": "Altres canvis", + "Overview": "Resum", + "Permalink to this definition": "Link permanent a aquesta definici\u00f3", + "Permalink to this headline": "Link permanent a aquest t\u00edtol", + "Please activate JavaScript to enable the search\n functionality.": "Activa JavaScript per utilitzar la funcionalitat\nde cerca.", + "Preparing search...": "", + "Previous topic": "Tema anterior", + "Quick search": "Cerca r\u00e0pida", + "Search": "Cerca", + "Search Page": "P\u00e0gina de Cerca", + "Search Results": "Resultats de la Cerca", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "Cerca dins de %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Mostra Codi Font", + "Table of Contents": "", + "This Page": "Aquesta P\u00e0gina", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "totes les funcions, classes, termes", + "can be huge": "pot ser gegant", + "last updated": "", + "lists all sections and subsections": "llista totes les seccions i subseccions", + "next chapter": "cap\u00edtol seg\u00fcent", + "previous chapter": "cap\u00edtol anterior", + "quick access to all modules": "acc\u00e9s r\u00e0pid a tots els m\u00f2duls", + "search": "cerca", + "search this documentation": "cerca aquesta documentaci\u00f3", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/ca/LC_MESSAGES/sphinx.po b/sphinx/locale/ca/LC_MESSAGES/sphinx.po index 6a8e317b1..9cbebc74a 100644 --- a/sphinx/locale/ca/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ca/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2009 msgid "" diff --git a/sphinx/locale/cak/LC_MESSAGES/sphinx.js b/sphinx/locale/cak/LC_MESSAGES/sphinx.js index 35e80d429..c75218b86 100644 --- a/sphinx/locale/cak/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/cak/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "None", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": ", pa", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "Konojel cholwuj", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "Cholwuj", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "Ruxaq wuj re'", "Welcome! This is": "\u00dctz apet\u00efk! Wawe' k'o", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": "ri wuj richin"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "None", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": ", pa", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "Konojel cholwuj", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "Cholwuj", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "Ruxaq wuj re'", + "Welcome! This is": "\u00dctz apet\u00efk! Wawe' k'o", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "ri wuj richin" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/cak/LC_MESSAGES/sphinx.po b/sphinx/locale/cak/LC_MESSAGES/sphinx.po index b729d5f1f..2ea8716e3 100644 --- a/sphinx/locale/cak/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/cak/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Julien Malard <julien.malard@mail.mcgill.ca>, 2019 msgid "" diff --git a/sphinx/locale/cs/LC_MESSAGES/sphinx.js b/sphinx/locale/cs/LC_MESSAGES/sphinx.js index dde27b37c..e17f2b69a 100644 --- a/sphinx/locale/cs/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/cs/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "cs", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": ", v ", "About these documents": "O t\u011bchto dokumentech", "Automatically generated list of changes in version %(version)s": "Automaticky generovan\u00fd seznam zm\u011bn ve verzi %(version)s", "C API changes": "Zm\u011bny API", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Sbalit bo\u010dn\u00ed li\u0161tu", "Complete Table of Contents": "Celkov\u00fd obsah", "Contents": "Obsah", "Copyright": "Ve\u0161ker\u00e1 pr\u00e1va vyhrazena", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Vytvo\u0159eno pomoc\u00ed <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Rozbalit bo\u010dn\u00ed li\u0161tu", "Full index on one page": "Cel\u00fd rejst\u0159\u00edk na jedn\u00e9 str\u00e1nce", "General Index": "Obecn\u00fd rejst\u0159\u00edk", "Global Module Index": "Celkov\u00fd rejst\u0159\u00edk modul\u016f", "Go": "OK", "Hide Search Matches": "Skr\u00fdt v\u00fdsledky vyhled\u00e1v\u00e1n\u00ed", "Index": "Rejst\u0159\u00edk", "Index – %(key)s": "Rejst\u0159\u00edk – %(key)s", "Index pages by letter": "Rejst\u0159\u00edk podle p\u00edsmene", "Indices and tables:": "Rejst\u0159\u00edky a tabulky:", "Last updated on %(last_updated)s.": "Aktualizov\u00e1no dne %(last_updated)s.", "Library changes": "Zm\u011bny v knihovn\u00e1ch", "Navigation": "Navigace", "Next topic": "Dal\u0161\u00ed t\u00e9ma", "Other changes": "Ostatn\u00ed zm\u011bny", "Overview": "P\u0159ehled", "Permalink to this definition": "Trval\u00fd odkaz na tuto definici", "Permalink to this headline": "Trval\u00fd odkaz na tento nadpis", "Please activate JavaScript to enable the search\n functionality.": "Pro podporu vyhled\u00e1v\u00e1n\u00ed aktivujte JavaScript.", "Preparing search...": "Vyhled\u00e1v\u00e1n\u00ed se p\u0159ipravuje...", "Previous topic": "P\u0159echoz\u00ed t\u00e9ma", "Quick search": "Rychl\u00e9 vyhled\u00e1v\u00e1n\u00ed", "Search": "Vyhled\u00e1v\u00e1n\u00ed", "Search Page": "Vyhled\u00e1vac\u00ed str\u00e1nka", "Search Results": "V\u00fdsledky vyhled\u00e1v\u00e1n\u00ed", "Search finished, found %s page(s) matching the search query.": "Vyhled\u00e1v\u00e1n\u00ed dokon\u010deno, str\u00e1nky odpov\u00eddaj\u00edc\u00ed hledan\u00e9mu v\u00fdrazu: %s.", "Search within %(docstitle)s": "Prohledat %(docstitle)s", "Searching": "Prob\u00edh\u00e1 vyhled\u00e1n\u00ed", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Uk\u00e1zat zdroj", "Table of Contents": "", "This Page": "Tato str\u00e1nka", "Welcome! This is": "V\u00edtejte! Toto je", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Vyhled\u00e1v\u00e1n\u00ed nenalezlo \u017e\u00e1dn\u00fd odpov\u00eddaj\u00edc\u00ed dokument. Ujist\u011bte se, \u017ee jste v\u0161echna slova zapsal/a spr\u00e1vn\u011b a \u017ee jste vybral/a dostatek kategori\u00ed.", "all functions, classes, terms": "v\u0161echny funkce, t\u0159\u00eddy, term\u00edny", "can be huge": "m\u016f\u017ee b\u00fdt obrovsk\u00fd", "last updated": "naposledy aktualizov\u00e1no", "lists all sections and subsections": "seznam v\u0161ech sekc\u00ed a podsekc\u00ed", "next chapter": "dal\u0161\u00ed kapitola", "previous chapter": "p\u0159edchoz\u00ed kapitola", "quick access to all modules": "rychl\u00fd p\u0159\u00edstup ke v\u0161em modul\u016fm", "search": "hledat", "search this documentation": "prohledat tuto dokumentaci", "the documentation for": "dokumentace pro"}, "plural_expr": "(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "cs", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": ", v ", + "About these documents": "O t\u011bchto dokumentech", + "Automatically generated list of changes in version %(version)s": "Automaticky generovan\u00fd seznam zm\u011bn ve verzi %(version)s", + "C API changes": "Zm\u011bny API", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Sbalit bo\u010dn\u00ed li\u0161tu", + "Complete Table of Contents": "Celkov\u00fd obsah", + "Contents": "Obsah", + "Copyright": "Ve\u0161ker\u00e1 pr\u00e1va vyhrazena", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Vytvo\u0159eno pomoc\u00ed <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Rozbalit bo\u010dn\u00ed li\u0161tu", + "Full index on one page": "Cel\u00fd rejst\u0159\u00edk na jedn\u00e9 str\u00e1nce", + "General Index": "Obecn\u00fd rejst\u0159\u00edk", + "Global Module Index": "Celkov\u00fd rejst\u0159\u00edk modul\u016f", + "Go": "OK", + "Hide Search Matches": "Skr\u00fdt v\u00fdsledky vyhled\u00e1v\u00e1n\u00ed", + "Index": "Rejst\u0159\u00edk", + "Index – %(key)s": "Rejst\u0159\u00edk – %(key)s", + "Index pages by letter": "Rejst\u0159\u00edk podle p\u00edsmene", + "Indices and tables:": "Rejst\u0159\u00edky a tabulky:", + "Last updated on %(last_updated)s.": "Aktualizov\u00e1no dne %(last_updated)s.", + "Library changes": "Zm\u011bny v knihovn\u00e1ch", + "Navigation": "Navigace", + "Next topic": "Dal\u0161\u00ed t\u00e9ma", + "Other changes": "Ostatn\u00ed zm\u011bny", + "Overview": "P\u0159ehled", + "Permalink to this definition": "Trval\u00fd odkaz na tuto definici", + "Permalink to this headline": "Trval\u00fd odkaz na tento nadpis", + "Please activate JavaScript to enable the search\n functionality.": "Pro podporu vyhled\u00e1v\u00e1n\u00ed aktivujte JavaScript.", + "Preparing search...": "Vyhled\u00e1v\u00e1n\u00ed se p\u0159ipravuje...", + "Previous topic": "P\u0159echoz\u00ed t\u00e9ma", + "Quick search": "Rychl\u00e9 vyhled\u00e1v\u00e1n\u00ed", + "Search": "Vyhled\u00e1v\u00e1n\u00ed", + "Search Page": "Vyhled\u00e1vac\u00ed str\u00e1nka", + "Search Results": "V\u00fdsledky vyhled\u00e1v\u00e1n\u00ed", + "Search finished, found %s page(s) matching the search query.": "Vyhled\u00e1v\u00e1n\u00ed dokon\u010deno, str\u00e1nky odpov\u00eddaj\u00edc\u00ed hledan\u00e9mu v\u00fdrazu: %s.", + "Search within %(docstitle)s": "Prohledat %(docstitle)s", + "Searching": "Prob\u00edh\u00e1 vyhled\u00e1n\u00ed", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Uk\u00e1zat zdroj", + "Table of Contents": "", + "This Page": "Tato str\u00e1nka", + "Welcome! This is": "V\u00edtejte! Toto je", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Vyhled\u00e1v\u00e1n\u00ed nenalezlo \u017e\u00e1dn\u00fd odpov\u00eddaj\u00edc\u00ed dokument. Ujist\u011bte se, \u017ee jste v\u0161echna slova zapsal/a spr\u00e1vn\u011b a \u017ee jste vybral/a dostatek kategori\u00ed.", + "all functions, classes, terms": "v\u0161echny funkce, t\u0159\u00eddy, term\u00edny", + "can be huge": "m\u016f\u017ee b\u00fdt obrovsk\u00fd", + "last updated": "naposledy aktualizov\u00e1no", + "lists all sections and subsections": "seznam v\u0161ech sekc\u00ed a podsekc\u00ed", + "next chapter": "dal\u0161\u00ed kapitola", + "previous chapter": "p\u0159edchoz\u00ed kapitola", + "quick access to all modules": "rychl\u00fd p\u0159\u00edstup ke v\u0161em modul\u016fm", + "search": "hledat", + "search this documentation": "prohledat tuto dokumentaci", + "the documentation for": "dokumentace pro" + }, + "plural_expr": "(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3" +});
\ No newline at end of file diff --git a/sphinx/locale/cs/LC_MESSAGES/sphinx.po b/sphinx/locale/cs/LC_MESSAGES/sphinx.po index 8952713e1..1e7890782 100644 --- a/sphinx/locale/cs/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/cs/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2008 # Vilibald W. <vilibald.wanca@gmail.com>, 2014-2015 diff --git a/sphinx/locale/cy/LC_MESSAGES/sphinx.js b/sphinx/locale/cy/LC_MESSAGES/sphinx.js index 5f3f30df9..c02b2098b 100644 --- a/sphinx/locale/cy/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/cy/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "cy", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": ", yn ", "About these documents": "Yngl\u0177n \u00e2'r dogfennau hyn", "Automatically generated list of changes in version %(version)s": "Rhestr o newidiadau yn fersiwn %(version)s wedi'i cynhyrchu'n awtomatig", "C API changes": "Newidiadau i'r C-API", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Cyfangu'r bar ochr", "Complete Table of Contents": "Tabl Cynnwys Llawn", "Contents": "Cynnwys", "Copyright": "Hawlfraint", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Cr\u8c37wyd gan ddefnyddio <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s", "Expand sidebar": "Ehangu'r bar ochr", "Full index on one page": "Indecs llawn ar un tudalen", "General Index": "Indecs cyffredinol", "Global Module Index": "Indecs Modiwl Byd-Eang", "Go": "Ewch", "Hide Search Matches": "Cuddio Canlyniadau Chwilio", "Index": "Indecs", "Index – %(key)s": "Indecs – %(key)s", "Index pages by letter": "Indecs tudalennau gan lythyren", "Indices and tables:": "Indecsau a tablau:", "Last updated on %(last_updated)s.": "Diweddarwyd yn ddiwethaf ar %(last_updated)s.", "Library changes": "Newidiadau i'r llyfrgell", "Navigation": "Llywio", "Next topic": "Pwnc nesaf", "Other changes": "Newidiadau arall", "Overview": "Trosolwg", "Permalink to this definition": "Permalink i'r diffiniad hwn", "Permalink to this headline": "Permalink i'r pennawd hwn", "Please activate JavaScript to enable the search\n functionality.": "Trwoch JavaScript ymlaen i alluogi'r chwilio.", "Preparing search...": "Paratoi chwilio...", "Previous topic": "Pwnc blaenorol", "Quick search": "Chwilio cyflym", "Search": "Chwilio", "Search Page": "Tudalen Chwilio", "Search Results": "Canlyniadau chwilio", "Search finished, found %s page(s) matching the search query.": "Chwiliad wedi gorffen, wedi ffeindio %s tudalen(nau) yn cyfateb a'r ymholiad chwilio.", "Search within %(docstitle)s": "Chwilio o fewn %(docstitle)s", "Searching": "Yn chwilio", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Dangos Ffynhonell", "Table of Contents": "", "This Page": "Y Dudalen Hon", "Welcome! This is": "Croeso! Dyma", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Nid yw eich chwiliad yn cyfateb unrhyw ddogfennau. Gwnewch yn si\u0175r fod pob gair wedi'i sillafu'n gywir, ac eich bod wedi dewis digon o gategor\u00efau.", "all functions, classes, terms": "holl ffwythiannau, dosbarthau a thermau", "can be huge": "gall fod yn enfawr", "last updated": "diweddarwyd yn ddiwethaf", "lists all sections and subsections": "rhestru holl adrannau ac isadrannau", "next chapter": "pennod nesaf", "previous chapter": "pennod blaenorol", "quick access to all modules": "mynediad cloi i bob modiwl", "search": "chwilio", "search this documentation": "chwiliwch y ddogfennaeth", "the documentation for": "y dogfennaeth am"}, "plural_expr": "(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "cy", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": ", yn ", + "About these documents": "Yngl\u0177n \u00e2'r dogfennau hyn", + "Automatically generated list of changes in version %(version)s": "Rhestr o newidiadau yn fersiwn %(version)s wedi'i cynhyrchu'n awtomatig", + "C API changes": "Newidiadau i'r C-API", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Cyfangu'r bar ochr", + "Complete Table of Contents": "Tabl Cynnwys Llawn", + "Contents": "Cynnwys", + "Copyright": "Hawlfraint", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Cr\u8c37wyd gan ddefnyddio <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s", + "Expand sidebar": "Ehangu'r bar ochr", + "Full index on one page": "Indecs llawn ar un tudalen", + "General Index": "Indecs cyffredinol", + "Global Module Index": "Indecs Modiwl Byd-Eang", + "Go": "Ewch", + "Hide Search Matches": "Cuddio Canlyniadau Chwilio", + "Index": "Indecs", + "Index – %(key)s": "Indecs – %(key)s", + "Index pages by letter": "Indecs tudalennau gan lythyren", + "Indices and tables:": "Indecsau a tablau:", + "Last updated on %(last_updated)s.": "Diweddarwyd yn ddiwethaf ar %(last_updated)s.", + "Library changes": "Newidiadau i'r llyfrgell", + "Navigation": "Llywio", + "Next topic": "Pwnc nesaf", + "Other changes": "Newidiadau arall", + "Overview": "Trosolwg", + "Permalink to this definition": "Permalink i'r diffiniad hwn", + "Permalink to this headline": "Permalink i'r pennawd hwn", + "Please activate JavaScript to enable the search\n functionality.": "Trwoch JavaScript ymlaen i alluogi'r chwilio.", + "Preparing search...": "Paratoi chwilio...", + "Previous topic": "Pwnc blaenorol", + "Quick search": "Chwilio cyflym", + "Search": "Chwilio", + "Search Page": "Tudalen Chwilio", + "Search Results": "Canlyniadau chwilio", + "Search finished, found %s page(s) matching the search query.": "Chwiliad wedi gorffen, wedi ffeindio %s tudalen(nau) yn cyfateb a'r ymholiad chwilio.", + "Search within %(docstitle)s": "Chwilio o fewn %(docstitle)s", + "Searching": "Yn chwilio", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Dangos Ffynhonell", + "Table of Contents": "", + "This Page": "Y Dudalen Hon", + "Welcome! This is": "Croeso! Dyma", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Nid yw eich chwiliad yn cyfateb unrhyw ddogfennau. Gwnewch yn si\u0175r fod pob gair wedi'i sillafu'n gywir, ac eich bod wedi dewis digon o gategor\u00efau.", + "all functions, classes, terms": "holl ffwythiannau, dosbarthau a thermau", + "can be huge": "gall fod yn enfawr", + "last updated": "diweddarwyd yn ddiwethaf", + "lists all sections and subsections": "rhestru holl adrannau ac isadrannau", + "next chapter": "pennod nesaf", + "previous chapter": "pennod blaenorol", + "quick access to all modules": "mynediad cloi i bob modiwl", + "search": "chwilio", + "search this documentation": "chwiliwch y ddogfennaeth", + "the documentation for": "y dogfennaeth am" + }, + "plural_expr": "(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3" +});
\ No newline at end of file diff --git a/sphinx/locale/cy/LC_MESSAGES/sphinx.po b/sphinx/locale/cy/LC_MESSAGES/sphinx.po index 12f2aecd2..19a4c83d3 100644 --- a/sphinx/locale/cy/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/cy/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2016 # Geraint Palmer <palmer.geraint@googlemail.com>, 2016 diff --git a/sphinx/locale/da/LC_MESSAGES/sphinx.js b/sphinx/locale/da/LC_MESSAGES/sphinx.js index 7bb9d94b1..1e6aa95c7 100644 --- a/sphinx/locale/da/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/da/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "da", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Ophavsret</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Ophavsret %(copyright)s.", ", in ": ", i", "About these documents": "Om disse dokumenter", "Automatically generated list of changes in version %(version)s": "Automatisk oprettet liste af \u00e6ndringer i version %(version)s", "C API changes": "\u00c6ndringer i C-API", "Changes in Version %(version)s — %(docstitle)s": "\u00c6ndringer i version %(version)s — %(docstitle)s", "Collapse sidebar": "Sammenfold sidebj\u00e6lke", "Complete Table of Contents": "Fuldst\u00e6ndig indholdsfortegnelse", "Contents": "Indhold", "Copyright": "Ophavsret", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Bygget med <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Udfold sidebj\u00e6lke", "Full index on one page": "Fuldt indeks p\u00e5 \u00e9n side", "General Index": "Generelt indeks", "Global Module Index": "Globalt modulindeks", "Go": "S\u00f8g", "Hide Search Matches": "Skjul s\u00f8geresultater", "Index": "Indeks", "Index – %(key)s": "Indeks – %(key)s", "Index pages by letter": "Indeks\u00e9r sider efter bogstav", "Indices and tables:": "Indeks og tabeller:", "Last updated on %(last_updated)s.": "Sidst opdateret %(last_updated)s.", "Library changes": "Biblioteks\u00e6ndringer", "Navigation": "Navigation", "Next topic": "N\u00e6ste emne", "Other changes": "Andre \u00e6ndringer", "Overview": "Oversigt", "Permalink to this definition": "Permalink til denne definition", "Permalink to this headline": "Permalink til denne overskrift", "Please activate JavaScript to enable the search\n functionality.": "Aktiv\u00e9r venligst JavaScript for at aktivere\n s\u00f8gefunktionalitet.", "Preparing search...": "Forbereder s\u00f8gning...", "Previous topic": "Forrige emne", "Quick search": "Hurtig s\u00f8gning", "Search": "S\u00f8g", "Search Page": "S\u00f8geside", "Search Results": "S\u00f8geresultater", "Search finished, found %s page(s) matching the search query.": "S\u00f8gning f\u00e6rdig, fandt %s sider der matcher s\u00f8geforesp\u00f8rgslen.", "Search within %(docstitle)s": "S\u00f8g i %(docstitle)s", "Searching": "S\u00f8ger", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Vis kilde", "Table of Contents": "", "This Page": "Denne side", "Welcome! This is": "Velkommen! Dette er", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Din s\u00f8gning matchede ikke nogen dokumenter. Sikr dig at alle ord er stavet korrekt og at du har valgt nok kategorier.", "all functions, classes, terms": "alle funktioner, klasser, begreber", "can be huge": "kan v\u00e6re enormt", "last updated": "sidst opdateret", "lists all sections and subsections": "viser alle afsnit og underafsnit", "next chapter": "n\u00e6ste kapitel", "previous chapter": "forrige kapitel", "quick access to all modules": "hurtig adgang til alle moduler", "search": "s\u00f8g", "search this documentation": "s\u00f8g i denne dokumentation", "the documentation for": "dokumentationen for"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "da", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Ophavsret</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Ophavsret %(copyright)s.", + ", in ": ", i", + "About these documents": "Om disse dokumenter", + "Automatically generated list of changes in version %(version)s": "Automatisk oprettet liste af \u00e6ndringer i version %(version)s", + "C API changes": "\u00c6ndringer i C-API", + "Changes in Version %(version)s — %(docstitle)s": "\u00c6ndringer i version %(version)s — %(docstitle)s", + "Collapse sidebar": "Sammenfold sidebj\u00e6lke", + "Complete Table of Contents": "Fuldst\u00e6ndig indholdsfortegnelse", + "Contents": "Indhold", + "Copyright": "Ophavsret", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Bygget med <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Udfold sidebj\u00e6lke", + "Full index on one page": "Fuldt indeks p\u00e5 \u00e9n side", + "General Index": "Generelt indeks", + "Global Module Index": "Globalt modulindeks", + "Go": "S\u00f8g", + "Hide Search Matches": "Skjul s\u00f8geresultater", + "Index": "Indeks", + "Index – %(key)s": "Indeks – %(key)s", + "Index pages by letter": "Indeks\u00e9r sider efter bogstav", + "Indices and tables:": "Indeks og tabeller:", + "Last updated on %(last_updated)s.": "Sidst opdateret %(last_updated)s.", + "Library changes": "Biblioteks\u00e6ndringer", + "Navigation": "Navigation", + "Next topic": "N\u00e6ste emne", + "Other changes": "Andre \u00e6ndringer", + "Overview": "Oversigt", + "Permalink to this definition": "Permalink til denne definition", + "Permalink to this headline": "Permalink til denne overskrift", + "Please activate JavaScript to enable the search\n functionality.": "Aktiv\u00e9r venligst JavaScript for at aktivere\n s\u00f8gefunktionalitet.", + "Preparing search...": "Forbereder s\u00f8gning...", + "Previous topic": "Forrige emne", + "Quick search": "Hurtig s\u00f8gning", + "Search": "S\u00f8g", + "Search Page": "S\u00f8geside", + "Search Results": "S\u00f8geresultater", + "Search finished, found %s page(s) matching the search query.": "S\u00f8gning f\u00e6rdig, fandt %s sider der matcher s\u00f8geforesp\u00f8rgslen.", + "Search within %(docstitle)s": "S\u00f8g i %(docstitle)s", + "Searching": "S\u00f8ger", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Vis kilde", + "Table of Contents": "", + "This Page": "Denne side", + "Welcome! This is": "Velkommen! Dette er", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Din s\u00f8gning matchede ikke nogen dokumenter. Sikr dig at alle ord er stavet korrekt og at du har valgt nok kategorier.", + "all functions, classes, terms": "alle funktioner, klasser, begreber", + "can be huge": "kan v\u00e6re enormt", + "last updated": "sidst opdateret", + "lists all sections and subsections": "viser alle afsnit og underafsnit", + "next chapter": "n\u00e6ste kapitel", + "previous chapter": "forrige kapitel", + "quick access to all modules": "hurtig adgang til alle moduler", + "search": "s\u00f8g", + "search this documentation": "s\u00f8g i denne dokumentation", + "the documentation for": "dokumentationen for" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/da/LC_MESSAGES/sphinx.po b/sphinx/locale/da/LC_MESSAGES/sphinx.po index 317b832d2..47fcbfd6f 100644 --- a/sphinx/locale/da/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/da/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # askhl <asklarsen@gmail.com>, 2010-2011 # Jakob Lykke Andersen <jakob@caput.dk>, 2014,2016 diff --git a/sphinx/locale/de/LC_MESSAGES/sphinx.js b/sphinx/locale/de/LC_MESSAGES/sphinx.js index b6390e636..86a610d8a 100644 --- a/sphinx/locale/de/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/de/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "de", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": ", in ", "About these documents": "\u00dcber dieses Dokument", "Automatically generated list of changes in version %(version)s": "Automatisch generierte Liste der \u00c4nderungen in Version %(version)s", "C API changes": "C API-\u00c4nderungen", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Seitenleiste einklappen", "Complete Table of Contents": "Vollst\u00e4ndiges Inhaltsverzeichnis", "Contents": "Inhalt", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Mit <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s erstellt.", "Expand sidebar": "Seitenleiste ausklappen", "Full index on one page": "Gesamtes Stichwortverzeichnis auf einer Seite", "General Index": "Stichwortverzeichnis", "Global Module Index": "Globaler Modulindex", "Go": "Los", "Hide Search Matches": "Suchergebnisse ausblenden", "Index": "Stichwortverzeichnis", "Index – %(key)s": "Stichwortverzeichnis – %(key)s", "Index pages by letter": "Stichwortverzeichnis nach Anfangsbuchstabe", "Indices and tables:": "Verzeichnisse und Tabellen:", "Last updated on %(last_updated)s.": "Zuletzt aktualisiert am %(last_updated)s.", "Library changes": "Bibliotheks-\u00c4nderungen", "Navigation": "Navigation", "Next topic": "N\u00e4chstes Thema", "Other changes": "Andere \u00c4nderungen", "Overview": "\u00dcbersicht", "Permalink to this definition": "Link zu dieser Definition", "Permalink to this headline": "Link zu dieser \u00dcberschrift", "Please activate JavaScript to enable the search\n functionality.": "Bitte aktivieren Sie JavaScript, wenn Sie die Suchfunktion nutzen wollen.", "Preparing search...": "Suche wird vorbereitet...", "Previous topic": "Vorheriges Thema", "Quick search": "Schnellsuche", "Search": "Suche", "Search Page": "Suche", "Search Results": "Suchergebnisse", "Search finished, found %s page(s) matching the search query.": "Die Suche ist fertig, es wurde(n) %s Seite(n) mit Treffern gefunden.", "Search within %(docstitle)s": "Suche in %(docstitle)s", "Searching": "Suchen", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Quellcode anzeigen", "Table of Contents": "Inhaltsverzeichnis", "This Page": "Diese Seite", "Welcome! This is": "Willkommen! Dies ist", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Ihre Suche ergab keine Treffer. Bitte stellen Sie sicher, dass alle W\u00f6rter richtig geschrieben sind und gen\u00fcgend Kategorien ausgew\u00e4hlt sind.", "all functions, classes, terms": "alle Funktionen, Klassen, Begriffe", "can be huge": "kann gro\u00df sein", "last updated": "zuletzt aktualisiert", "lists all sections and subsections": "Liste aller Kapitel und Unterkapitel", "next chapter": "n\u00e4chstes Kapitel", "previous chapter": "vorheriges Kapitel", "quick access to all modules": "schneller Zugriff auf alle Module", "search": "suchen", "search this documentation": "durchsuche diese Dokumentation", "the documentation for": "die Dokumentation f\u00fcr"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "de", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": ", in ", + "About these documents": "\u00dcber dieses Dokument", + "Automatically generated list of changes in version %(version)s": "Automatisch generierte Liste der \u00c4nderungen in Version %(version)s", + "C API changes": "C API-\u00c4nderungen", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Seitenleiste einklappen", + "Complete Table of Contents": "Vollst\u00e4ndiges Inhaltsverzeichnis", + "Contents": "Inhalt", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Mit <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s erstellt.", + "Expand sidebar": "Seitenleiste ausklappen", + "Full index on one page": "Gesamtes Stichwortverzeichnis auf einer Seite", + "General Index": "Stichwortverzeichnis", + "Global Module Index": "Globaler Modulindex", + "Go": "Los", + "Hide Search Matches": "Suchergebnisse ausblenden", + "Index": "Stichwortverzeichnis", + "Index – %(key)s": "Stichwortverzeichnis – %(key)s", + "Index pages by letter": "Stichwortverzeichnis nach Anfangsbuchstabe", + "Indices and tables:": "Verzeichnisse und Tabellen:", + "Last updated on %(last_updated)s.": "Zuletzt aktualisiert am %(last_updated)s.", + "Library changes": "Bibliotheks-\u00c4nderungen", + "Navigation": "Navigation", + "Next topic": "N\u00e4chstes Thema", + "Other changes": "Andere \u00c4nderungen", + "Overview": "\u00dcbersicht", + "Permalink to this definition": "Link zu dieser Definition", + "Permalink to this headline": "Link zu dieser \u00dcberschrift", + "Please activate JavaScript to enable the search\n functionality.": "Bitte aktivieren Sie JavaScript, wenn Sie die Suchfunktion nutzen wollen.", + "Preparing search...": "Suche wird vorbereitet...", + "Previous topic": "Vorheriges Thema", + "Quick search": "Schnellsuche", + "Search": "Suche", + "Search Page": "Suche", + "Search Results": "Suchergebnisse", + "Search finished, found %s page(s) matching the search query.": "Die Suche ist fertig, es wurde(n) %s Seite(n) mit Treffern gefunden.", + "Search within %(docstitle)s": "Suche in %(docstitle)s", + "Searching": "Suchen", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Quellcode anzeigen", + "Table of Contents": "Inhaltsverzeichnis", + "This Page": "Diese Seite", + "Welcome! This is": "Willkommen! Dies ist", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Ihre Suche ergab keine Treffer. Bitte stellen Sie sicher, dass alle W\u00f6rter richtig geschrieben sind und gen\u00fcgend Kategorien ausgew\u00e4hlt sind.", + "all functions, classes, terms": "alle Funktionen, Klassen, Begriffe", + "can be huge": "kann gro\u00df sein", + "last updated": "zuletzt aktualisiert", + "lists all sections and subsections": "Liste aller Kapitel und Unterkapitel", + "next chapter": "n\u00e4chstes Kapitel", + "previous chapter": "vorheriges Kapitel", + "quick access to all modules": "schneller Zugriff auf alle Module", + "search": "suchen", + "search this documentation": "durchsuche diese Dokumentation", + "the documentation for": "die Dokumentation f\u00fcr" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/de/LC_MESSAGES/sphinx.po b/sphinx/locale/de/LC_MESSAGES/sphinx.po index 8d5cd4e43..2eaab8597 100644 --- a/sphinx/locale/de/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/de/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Georg Brandl <g.brandl@gmx.net>, 2013-2015 # Jean-François B. <jfbu@free.fr>, 2018 diff --git a/sphinx/locale/el/LC_MESSAGES/sphinx.js b/sphinx/locale/el/LC_MESSAGES/sphinx.js index 2bdbfeaec..bc1716f2f 100644 --- a/sphinx/locale/el/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/el/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "el", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a>%(copyright)s", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", \u03c3\u03c4\u03bf ", "About these documents": "\u03a3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac \u03bc\u03b5 \u03b1\u03c5\u03c4\u03ac \u03c4\u03b1 \u03ba\u03b5\u03af\u03bc\u03b5\u03bd\u03b1", "Automatically generated list of changes in version %(version)s": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1 \u03c0\u03b1\u03c1\u03b1\u03b3\u03cc\u03bc\u03b5\u03bd\u03b7 \u03bb\u03af\u03c3\u03c4\u03b1 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ce\u03bd \u03c3\u03c4\u03b7\u03bd \u03ad\u03ba\u03b4\u03bf\u03c3\u03b7 %(version)s", "C API changes": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2 \u03c3\u03c4\u03bf API \u03c4\u03b7\u03c2 C", "Changes in Version %(version)s — %(docstitle)s": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2 \u03c3\u03c4\u03b7\u03bd \u0388\u03ba\u03b4\u03bf\u03c3\u03b7 %(version)s —'\n%(docstitle)s", "Collapse sidebar": "\u039a\u03bb\u03b5\u03af\u03c3\u03b9\u03bc\u03bf \u03c0\u03bb\u03b1\u03ca\u03bd\u03ae\u03c2 \u03bc\u03c0\u03ac\u03c1\u03b1\u03c2", "Complete Table of Contents": "\u03a0\u03bb\u03ae\u03c1\u03b7\u03c2 \u03a0\u03af\u03bd\u03b1\u03ba\u03b1\u03c2 \u03a0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd", "Contents": "\u03a0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03b1", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03b8\u03b7\u03ba\u03b5 \u03bc\u03b5 \u03c4\u03bf <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1 \u03c0\u03bb\u03b1\u03ca\u03bd\u03ae\u03c2 \u03bc\u03c0\u03ac\u03c1\u03b1\u03c2", "Full index on one page": "\u03a0\u03bb\u03ae\u03c1\u03b5\u03c2 \u03b5\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf \u03c3\u03b5 \u03bc\u03af\u03b1 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1", "General Index": "\u039a\u03b5\u03bd\u03c4\u03c1\u03b9\u03ba\u03cc \u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf\u03bf", "Global Module Index": "\u039a\u03b1\u03b8\u03bf\u03bb\u03b9\u03ba\u03cc \u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf \u039c\u03bf\u03bd\u03ac\u03b4\u03c9\u03bd", "Go": "\u03a0\u03ac\u03bc\u03b5", "Hide Search Matches": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u0395\u03c5\u03c1\u03b5\u03b8\u03ad\u03bd\u03c4\u03c9\u03bd \u0391\u03bd\u03b1\u03b6\u03b7\u03c4\u03ae\u03c3\u03b5\u03c9\u03bd", "Index": "\u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf", "Index – %(key)s": "\u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf – %(key)s", "Index pages by letter": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b5\u03c2 \u03b5\u03c5\u03c1\u03b5\u03c4\u03b7\u03c1\u03af\u03bf\u03c5 \u03b1\u03bd\u03ac \u03b3\u03c1\u03ac\u03bc\u03bc\u03b1", "Indices and tables:": "\u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03b1 \u03ba\u03b1\u03b9 \u03c0\u03af\u03bd\u03b1\u03ba\u03b5\u03c2:", "Last updated on %(last_updated)s.": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03b5\u03bd\u03b7\u03bc\u03ad\u03c1\u03c9\u03c3\u03b7 \u03c3\u03c4\u03b9\u03c2 %(last_updated)s.", "Library changes": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7\u03c2", "Navigation": "\u03a0\u03bb\u03bf\u03ae\u03b3\u03b7\u03c3\u03b7", "Next topic": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u03b8\u03ad\u03bc\u03b1", "Other changes": "\u0386\u03bb\u03bb\u03b5\u03c2 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2", "Overview": "\u0395\u03c0\u03b9\u03c3\u03ba\u03cc\u03c0\u03b7\u03c3\u03b7", "Permalink to this definition": "\u039c\u03cc\u03bd\u03b9\u03bc\u03bf\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03c2 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03bf\u03c1\u03b9\u03c3\u03bc\u03cc", "Permalink to this headline": "\u039c\u03cc\u03bd\u03b9\u03bc\u03bf\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03c2 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7\u03bd \u03ba\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1", "Please activate JavaScript to enable the search\n functionality.": "\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce, \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b7 JavaScript \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae \u03b7 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1\n \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2.", "Preparing search...": "\u03a0\u03c1\u03bf\u03b5\u03c4\u03bf\u03b9\u03bc\u03b1\u03c3\u03af\u03b1 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2...", "Previous topic": "\u03a0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf \u03b8\u03ad\u03bc\u03b1", "Quick search": "\u03a3\u03cd\u03bd\u03c4\u03bf\u03bc\u03b7 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", "Search": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", "Search Page": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2", "Search Results": "\u0391\u03c0\u03bf\u03c4\u03b5\u03bb\u03ad\u03c3\u03bc\u03b1\u03c4\u03b1 \u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2", "Search finished, found %s page(s) matching the search query.": "\u0397 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03bf\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5, \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b5/\u03b1\u03bd %s \u03c3\u03b5\u03bb\u03af\u03b4\u03b1/\u03b5\u03c2 \u03bc\u03b5 \u03b2\u03ac\u03c3\u03b7 \u03c4\u03bf\u03c5\u03c2 \u03cc\u03c1\u03bf\u03c5\u03c2 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2.", "Search within %(docstitle)s": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03c3\u03c4\u03bf %(docstitle)s", "Searching": "\u0395\u03ba\u03c4\u03b5\u03bb\u03b5\u03af\u03c4\u03b1\u03b9 \u03b7 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u03a0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ae \u03ba\u03ce\u03b4\u03b9\u03ba\u03b1", "Table of Contents": "\u03a0\u03af\u03bd\u03b1\u03ba\u03b1\u03c2 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd", "This Page": "\u0391\u03c5\u03c4\u03ae \u03b7 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1", "Welcome! This is": "\u039a\u03b1\u03bb\u03c9\u03c3\u03ae\u03c1\u03b8\u03b1\u03c4\u03b5! \u0391\u03c5\u03c4\u03ae \u03b5\u03af\u03bd\u03b1\u03b9", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u0397 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03ae \u03c3\u03b1\u03c2 \u03b4\u03b5\u03bd \u03c4\u03b1\u03c5\u03c4\u03bf\u03c0\u03bf\u03b9\u03ae\u03b8\u03b7\u03ba\u03b5 \u03bc\u03b5 \u03ba\u03b1\u03bd\u03ad\u03bd\u03b1 \u03ba\u03b5\u03af\u03bc\u03b5\u03bd\u03bf. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce, \u03b5\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03b9\u03ce\u03c3\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bb\u03ad\u03be\u03b5\u03b9\u03c2 \u03ad\u03c7\u03bf\u03c5\u03bd \u03c4\u03b7 \u03c3\u03c9\u03c3\u03c4\u03ae \u03bf\u03c1\u03b8\u03bf\u03b3\u03c1\u03b1\u03c6\u03af\u03b1 \u03ba\u03b1\u03b9 \u03cc\u03c4\u03b9 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b5\u03c0\u03b9\u03bb\u03ad\u03be\u03b5\u03b9\u03c2 \u03b1\u03c1\u03ba\u03b5\u03c4\u03ad\u03c2 \u03ba\u03b1\u03c4\u03b7\u03b3\u03bf\u03c1\u03af\u03b5\u03c2.", "all functions, classes, terms": "\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03c3\u03c5\u03bd\u03b1\u03c1\u03c4\u03ae\u03c3\u03b5\u03b9\u03c2, \u03ba\u03bb\u03ac\u03c3\u03b5\u03b9\u03c2, \u03cc\u03c1\u03bf\u03b9", "can be huge": "\u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03c4\u03b5\u03c1\u03ac\u03c3\u03c4\u03b9\u03bf", "last updated": "\u03c4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03b5\u03bd\u03b7\u03bc\u03ad\u03c1\u03c9\u03c3\u03b7", "lists all sections and subsections": "\u03b1\u03c0\u03b1\u03c1\u03b9\u03b8\u03bc\u03b5\u03af \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03ba\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03b1 \u03ba\u03b1\u03b9 \u03c5\u03c0\u03bf\u03ba\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03b1", "next chapter": "\u03b5\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u03ba\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03bf", "previous chapter": "\u03c0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf \u03ba\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03bf", "quick access to all modules": "\u03b3\u03c1\u03ae\u03b3\u03bf\u03c1\u03b7 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03b5 \u03cc\u03bb\u03b5\u03c2 \u03c4\u03b9\u03c2 \u03bc\u03bf\u03bd\u03ac\u03b4\u03b5\u03c2", "search": "\u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", "search this documentation": "\u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03b1\u03c5\u03c4\u03ae\u03c2 \u03c4\u03b7\u03c2 \u03c4\u03b5\u03ba\u03bc\u03b7\u03c1\u03af\u03c9\u03c3\u03b7\u03c2", "the documentation for": "\u03b7 \u03c4\u03b5\u03ba\u03bc\u03b7\u03c1\u03af\u03c9\u03c3\u03b7 \u03c4\u03bf\u03c5"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "el", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a>%(copyright)s", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", \u03c3\u03c4\u03bf ", + "About these documents": "\u03a3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac \u03bc\u03b5 \u03b1\u03c5\u03c4\u03ac \u03c4\u03b1 \u03ba\u03b5\u03af\u03bc\u03b5\u03bd\u03b1", + "Automatically generated list of changes in version %(version)s": "\u0391\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1 \u03c0\u03b1\u03c1\u03b1\u03b3\u03cc\u03bc\u03b5\u03bd\u03b7 \u03bb\u03af\u03c3\u03c4\u03b1 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ce\u03bd \u03c3\u03c4\u03b7\u03bd \u03ad\u03ba\u03b4\u03bf\u03c3\u03b7 %(version)s", + "C API changes": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2 \u03c3\u03c4\u03bf API \u03c4\u03b7\u03c2 C", + "Changes in Version %(version)s — %(docstitle)s": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2 \u03c3\u03c4\u03b7\u03bd \u0388\u03ba\u03b4\u03bf\u03c3\u03b7 %(version)s —'\n%(docstitle)s", + "Collapse sidebar": "\u039a\u03bb\u03b5\u03af\u03c3\u03b9\u03bc\u03bf \u03c0\u03bb\u03b1\u03ca\u03bd\u03ae\u03c2 \u03bc\u03c0\u03ac\u03c1\u03b1\u03c2", + "Complete Table of Contents": "\u03a0\u03bb\u03ae\u03c1\u03b7\u03c2 \u03a0\u03af\u03bd\u03b1\u03ba\u03b1\u03c2 \u03a0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd", + "Contents": "\u03a0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03b1", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03b8\u03b7\u03ba\u03b5 \u03bc\u03b5 \u03c4\u03bf <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "\u0386\u03bd\u03bf\u03b9\u03b3\u03bc\u03b1 \u03c0\u03bb\u03b1\u03ca\u03bd\u03ae\u03c2 \u03bc\u03c0\u03ac\u03c1\u03b1\u03c2", + "Full index on one page": "\u03a0\u03bb\u03ae\u03c1\u03b5\u03c2 \u03b5\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf \u03c3\u03b5 \u03bc\u03af\u03b1 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1", + "General Index": "\u039a\u03b5\u03bd\u03c4\u03c1\u03b9\u03ba\u03cc \u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf\u03bf", + "Global Module Index": "\u039a\u03b1\u03b8\u03bf\u03bb\u03b9\u03ba\u03cc \u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf \u039c\u03bf\u03bd\u03ac\u03b4\u03c9\u03bd", + "Go": "\u03a0\u03ac\u03bc\u03b5", + "Hide Search Matches": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u0395\u03c5\u03c1\u03b5\u03b8\u03ad\u03bd\u03c4\u03c9\u03bd \u0391\u03bd\u03b1\u03b6\u03b7\u03c4\u03ae\u03c3\u03b5\u03c9\u03bd", + "Index": "\u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf", + "Index – %(key)s": "\u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03bf – %(key)s", + "Index pages by letter": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b5\u03c2 \u03b5\u03c5\u03c1\u03b5\u03c4\u03b7\u03c1\u03af\u03bf\u03c5 \u03b1\u03bd\u03ac \u03b3\u03c1\u03ac\u03bc\u03bc\u03b1", + "Indices and tables:": "\u0395\u03c5\u03c1\u03b5\u03c4\u03ae\u03c1\u03b9\u03b1 \u03ba\u03b1\u03b9 \u03c0\u03af\u03bd\u03b1\u03ba\u03b5\u03c2:", + "Last updated on %(last_updated)s.": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03b5\u03bd\u03b7\u03bc\u03ad\u03c1\u03c9\u03c3\u03b7 \u03c3\u03c4\u03b9\u03c2 %(last_updated)s.", + "Library changes": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7\u03c2", + "Navigation": "\u03a0\u03bb\u03bf\u03ae\u03b3\u03b7\u03c3\u03b7", + "Next topic": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u03b8\u03ad\u03bc\u03b1", + "Other changes": "\u0386\u03bb\u03bb\u03b5\u03c2 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2", + "Overview": "\u0395\u03c0\u03b9\u03c3\u03ba\u03cc\u03c0\u03b7\u03c3\u03b7", + "Permalink to this definition": "\u039c\u03cc\u03bd\u03b9\u03bc\u03bf\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03c2 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03bf\u03c1\u03b9\u03c3\u03bc\u03cc", + "Permalink to this headline": "\u039c\u03cc\u03bd\u03b9\u03bc\u03bf\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03c2 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03ae\u03bd \u03c4\u03b7\u03bd \u03ba\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1", + "Please activate JavaScript to enable the search\n functionality.": "\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce, \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b7 JavaScript \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae \u03b7 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1\n \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2.", + "Preparing search...": "\u03a0\u03c1\u03bf\u03b5\u03c4\u03bf\u03b9\u03bc\u03b1\u03c3\u03af\u03b1 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2...", + "Previous topic": "\u03a0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf \u03b8\u03ad\u03bc\u03b1", + "Quick search": "\u03a3\u03cd\u03bd\u03c4\u03bf\u03bc\u03b7 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", + "Search": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", + "Search Page": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2", + "Search Results": "\u0391\u03c0\u03bf\u03c4\u03b5\u03bb\u03ad\u03c3\u03bc\u03b1\u03c4\u03b1 \u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2", + "Search finished, found %s page(s) matching the search query.": "\u0397 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03bf\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5, \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b5/\u03b1\u03bd %s \u03c3\u03b5\u03bb\u03af\u03b4\u03b1/\u03b5\u03c2 \u03bc\u03b5 \u03b2\u03ac\u03c3\u03b7 \u03c4\u03bf\u03c5\u03c2 \u03cc\u03c1\u03bf\u03c5\u03c2 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7\u03c2.", + "Search within %(docstitle)s": "\u0391\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03c3\u03c4\u03bf %(docstitle)s", + "Searching": "\u0395\u03ba\u03c4\u03b5\u03bb\u03b5\u03af\u03c4\u03b1\u03b9 \u03b7 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u03a0\u03c1\u03bf\u03b2\u03bf\u03bb\u03ae \u03ba\u03ce\u03b4\u03b9\u03ba\u03b1", + "Table of Contents": "\u03a0\u03af\u03bd\u03b1\u03ba\u03b1\u03c2 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd", + "This Page": "\u0391\u03c5\u03c4\u03ae \u03b7 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1", + "Welcome! This is": "\u039a\u03b1\u03bb\u03c9\u03c3\u03ae\u03c1\u03b8\u03b1\u03c4\u03b5! \u0391\u03c5\u03c4\u03ae \u03b5\u03af\u03bd\u03b1\u03b9", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u0397 \u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03ae \u03c3\u03b1\u03c2 \u03b4\u03b5\u03bd \u03c4\u03b1\u03c5\u03c4\u03bf\u03c0\u03bf\u03b9\u03ae\u03b8\u03b7\u03ba\u03b5 \u03bc\u03b5 \u03ba\u03b1\u03bd\u03ad\u03bd\u03b1 \u03ba\u03b5\u03af\u03bc\u03b5\u03bd\u03bf. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce, \u03b5\u03c0\u03b9\u03b2\u03b5\u03b2\u03b1\u03b9\u03ce\u03c3\u03c4\u03b5 \u03cc\u03c4\u03b9 \u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bb\u03ad\u03be\u03b5\u03b9\u03c2 \u03ad\u03c7\u03bf\u03c5\u03bd \u03c4\u03b7 \u03c3\u03c9\u03c3\u03c4\u03ae \u03bf\u03c1\u03b8\u03bf\u03b3\u03c1\u03b1\u03c6\u03af\u03b1 \u03ba\u03b1\u03b9 \u03cc\u03c4\u03b9 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b5\u03c0\u03b9\u03bb\u03ad\u03be\u03b5\u03b9\u03c2 \u03b1\u03c1\u03ba\u03b5\u03c4\u03ad\u03c2 \u03ba\u03b1\u03c4\u03b7\u03b3\u03bf\u03c1\u03af\u03b5\u03c2.", + "all functions, classes, terms": "\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03c3\u03c5\u03bd\u03b1\u03c1\u03c4\u03ae\u03c3\u03b5\u03b9\u03c2, \u03ba\u03bb\u03ac\u03c3\u03b5\u03b9\u03c2, \u03cc\u03c1\u03bf\u03b9", + "can be huge": "\u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03b5\u03af\u03bd\u03b1\u03b9 \u03c4\u03b5\u03c1\u03ac\u03c3\u03c4\u03b9\u03bf", + "last updated": "\u03c4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1 \u03b5\u03bd\u03b7\u03bc\u03ad\u03c1\u03c9\u03c3\u03b7", + "lists all sections and subsections": "\u03b1\u03c0\u03b1\u03c1\u03b9\u03b8\u03bc\u03b5\u03af \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03ba\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03b1 \u03ba\u03b1\u03b9 \u03c5\u03c0\u03bf\u03ba\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03b1", + "next chapter": "\u03b5\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf \u03ba\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03bf", + "previous chapter": "\u03c0\u03c1\u03bf\u03b7\u03b3\u03bf\u03cd\u03bc\u03b5\u03bd\u03bf \u03ba\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03bf", + "quick access to all modules": "\u03b3\u03c1\u03ae\u03b3\u03bf\u03c1\u03b7 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03b5 \u03cc\u03bb\u03b5\u03c2 \u03c4\u03b9\u03c2 \u03bc\u03bf\u03bd\u03ac\u03b4\u03b5\u03c2", + "search": "\u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7", + "search this documentation": "\u03b1\u03bd\u03b1\u03b6\u03ae\u03c4\u03b7\u03c3\u03b7 \u03b1\u03c5\u03c4\u03ae\u03c2 \u03c4\u03b7\u03c2 \u03c4\u03b5\u03ba\u03bc\u03b7\u03c1\u03af\u03c9\u03c3\u03b7\u03c2", + "the documentation for": "\u03b7 \u03c4\u03b5\u03ba\u03bc\u03b7\u03c1\u03af\u03c9\u03c3\u03b7 \u03c4\u03bf\u03c5" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/el/LC_MESSAGES/sphinx.po b/sphinx/locale/el/LC_MESSAGES/sphinx.po index 54eb341ec..03f5d01fe 100644 --- a/sphinx/locale/el/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/el/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Stelios Vitalis <liberostelios@gmail.com>, 2015 # tzoumakers tzoumakers <tzoumakersx@gmail.com>, 2019 diff --git a/sphinx/locale/eo/LC_MESSAGES/sphinx.js b/sphinx/locale/eo/LC_MESSAGES/sphinx.js index 184ab4aec..e5fbb0aa8 100644 --- a/sphinx/locale/eo/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/eo/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "eo", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "A\u016dtora rajto", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "Indico universala", "Global Module Index": "Universala modjulindico", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "Indico – %(key)s", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "Sekva temo", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "Anta\u016da temo", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "sekvo \u0109apitro", "previous chapter": "anta\u016da \u0109apitro", "quick access to all modules": "", "search": "ser\u0109u", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "eo", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "A\u016dtora rajto", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "Indico universala", + "Global Module Index": "Universala modjulindico", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "Indico – %(key)s", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "Sekva temo", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "Anta\u016da temo", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "sekvo \u0109apitro", + "previous chapter": "anta\u016da \u0109apitro", + "quick access to all modules": "", + "search": "ser\u0109u", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/eo/LC_MESSAGES/sphinx.po b/sphinx/locale/eo/LC_MESSAGES/sphinx.po index 6c94360c6..1af0769f3 100644 --- a/sphinx/locale/eo/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/eo/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Dinu Gherman <gherman@darwin.in-berlin.de>, 2014 msgid "" diff --git a/sphinx/locale/es/LC_MESSAGES/sphinx.js b/sphinx/locale/es/LC_MESSAGES/sphinx.js index fd4743269..3ddcced19 100644 --- a/sphinx/locale/es/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/es/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "es", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Derechos de autor</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Derechos de autor %(copyright)s.", ", in ": ", en ", "About these documents": "Sobre este documento", "Automatically generated list of changes in version %(version)s": "Lista de cambios generada autom\u00e1ticamente en la versi\u00f3n %(version)s", "C API changes": "Cambios en la API C", "Changes in Version %(version)s — %(docstitle)s": "Cambios en la versi\u00f3n %(version)s — %(docstitle)s", "Collapse sidebar": "Contraer barra lateral", "Complete Table of Contents": "\u00cdndice de contenidos completo", "Contents": "Contenidos", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Creado con <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Expandir barra lateral", "Full index on one page": "\u00cdndice completo en una p\u00e1gina", "General Index": "\u00cdndice General", "Global Module Index": "\u00cdndice Global de M\u00f3dulos", "Go": "Ir a", "Hide Search Matches": "Ocultar coincidencias de la b\u00fasqueda", "Index": "\u00cdndice", "Index – %(key)s": "\u00cdndice – %(key)s", "Index pages by letter": "\u00cdndice alfab\u00e9tico de p\u00e1ginas", "Indices and tables:": "\u00cdndices y tablas:", "Last updated on %(last_updated)s.": "Actualizado por \u00faltima vez en %(last_updated)s.", "Library changes": "Cambios en la biblioteca", "Navigation": "Navegaci\u00f3n", "Next topic": "Pr\u00f3ximo tema", "Other changes": "Otros cambios", "Overview": "Resumen", "Permalink to this definition": "Enlazar permanentemente con esta definici\u00f3n", "Permalink to this headline": "Enlazar permanentemente con este t\u00edtulo", "Please activate JavaScript to enable the search\n functionality.": "Por favor, active JavaScript para habilitar la funcionalidad\n de b\u00fasqueda.", "Preparing search...": "Preparando b\u00fasqueda...", "Previous topic": "Tema anterior", "Quick search": "B\u00fasqueda r\u00e1pida", "Search": "B\u00fasqueda", "Search Page": "P\u00e1gina de B\u00fasqueda", "Search Results": "Resultados de la b\u00fasqueda", "Search finished, found %s page(s) matching the search query.": "B\u00fasqueda finalizada, encontr\u00f3 %s p\u00e1gina(s) acorde con la consulta de b\u00fasqueda.", "Search within %(docstitle)s": "Buscar en %(docstitle)s", "Searching": "Buscando", "Searching for multiple words only shows matches that contain\n all words.": "La b\u00fasqueda de varias palabras solo muestra coincidencias que contienen\n todas las palabras.", "Show Source": "Mostrar el c\u00f3digo", "Table of Contents": "Tabla de contenido", "This Page": "Esta p\u00e1gina", "Welcome! This is": "\u00a1Bienvenido! Este es", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Su b\u00fasqueda no coincide con ning\u00fan documentos. Por favor, aseg\u00farese de que todas las palabras est\u00e9n correctamente escritas y que usted all\u00e1 seleccionado las suficientes categor\u00edas.", "all functions, classes, terms": "todas las funciones, clases, t\u00e9rminos", "can be huge": "puede ser muy grande", "last updated": "actualizado por \u00faltima vez el", "lists all sections and subsections": "muestra todas las secciones y subsecciones", "next chapter": "pr\u00f3ximo cap\u00edtulo", "previous chapter": "cap\u00edtulo anterior", "quick access to all modules": "acceso r\u00e1pido a todos los m\u00f3dulos", "search": "buscar", "search this documentation": "buscar en esta documentaci\u00f3n", "the documentation for": "la documentaci\u00f3n para"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "es", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Derechos de autor</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Derechos de autor %(copyright)s.", + ", in ": ", en ", + "About these documents": "Sobre este documento", + "Automatically generated list of changes in version %(version)s": "Lista de cambios generada autom\u00e1ticamente en la versi\u00f3n %(version)s", + "C API changes": "Cambios en la API C", + "Changes in Version %(version)s — %(docstitle)s": "Cambios en la versi\u00f3n %(version)s — %(docstitle)s", + "Collapse sidebar": "Contraer barra lateral", + "Complete Table of Contents": "\u00cdndice de contenidos completo", + "Contents": "Contenidos", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Creado con <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Expandir barra lateral", + "Full index on one page": "\u00cdndice completo en una p\u00e1gina", + "General Index": "\u00cdndice General", + "Global Module Index": "\u00cdndice Global de M\u00f3dulos", + "Go": "Ir a", + "Hide Search Matches": "Ocultar coincidencias de la b\u00fasqueda", + "Index": "\u00cdndice", + "Index – %(key)s": "\u00cdndice – %(key)s", + "Index pages by letter": "\u00cdndice alfab\u00e9tico de p\u00e1ginas", + "Indices and tables:": "\u00cdndices y tablas:", + "Last updated on %(last_updated)s.": "Actualizado por \u00faltima vez en %(last_updated)s.", + "Library changes": "Cambios en la biblioteca", + "Navigation": "Navegaci\u00f3n", + "Next topic": "Pr\u00f3ximo tema", + "Other changes": "Otros cambios", + "Overview": "Resumen", + "Permalink to this definition": "Enlazar permanentemente con esta definici\u00f3n", + "Permalink to this headline": "Enlazar permanentemente con este t\u00edtulo", + "Please activate JavaScript to enable the search\n functionality.": "Por favor, active JavaScript para habilitar la funcionalidad\n de b\u00fasqueda.", + "Preparing search...": "Preparando b\u00fasqueda...", + "Previous topic": "Tema anterior", + "Quick search": "B\u00fasqueda r\u00e1pida", + "Search": "B\u00fasqueda", + "Search Page": "P\u00e1gina de B\u00fasqueda", + "Search Results": "Resultados de la b\u00fasqueda", + "Search finished, found %s page(s) matching the search query.": "B\u00fasqueda finalizada, encontr\u00f3 %s p\u00e1gina(s) acorde con la consulta de b\u00fasqueda.", + "Search within %(docstitle)s": "Buscar en %(docstitle)s", + "Searching": "Buscando", + "Searching for multiple words only shows matches that contain\n all words.": "La b\u00fasqueda de varias palabras solo muestra coincidencias que contienen\n todas las palabras.", + "Show Source": "Mostrar el c\u00f3digo", + "Table of Contents": "Tabla de contenido", + "This Page": "Esta p\u00e1gina", + "Welcome! This is": "\u00a1Bienvenido! Este es", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Su b\u00fasqueda no coincide con ning\u00fan documentos. Por favor, aseg\u00farese de que todas las palabras est\u00e9n correctamente escritas y que usted all\u00e1 seleccionado las suficientes categor\u00edas.", + "all functions, classes, terms": "todas las funciones, clases, t\u00e9rminos", + "can be huge": "puede ser muy grande", + "last updated": "actualizado por \u00faltima vez el", + "lists all sections and subsections": "muestra todas las secciones y subsecciones", + "next chapter": "pr\u00f3ximo cap\u00edtulo", + "previous chapter": "cap\u00edtulo anterior", + "quick access to all modules": "acceso r\u00e1pido a todos los m\u00f3dulos", + "search": "buscar", + "search this documentation": "buscar en esta documentaci\u00f3n", + "the documentation for": "la documentaci\u00f3n para" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/es/LC_MESSAGES/sphinx.po b/sphinx/locale/es/LC_MESSAGES/sphinx.po index be149e88a..a01ae6c80 100644 --- a/sphinx/locale/es/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/es/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Edward Villegas-Pulgarin <cosmoscalibur@gmail.com>, 2018 # Edward Villegas-Pulgarin <cosmoscalibur@gmail.com>, 2019 diff --git a/sphinx/locale/et/LC_MESSAGES/sphinx.js b/sphinx/locale/et/LC_MESSAGES/sphinx.js index c50c7dde8..a9aea496e 100644 --- a/sphinx/locale/et/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/et/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "et", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s &8212; %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Autori\u00f5igused</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Autori\u00f5igused %(copyright)s.", ", in ": "", "About these documents": "Info selle dokumentatsiooni kohta", "Automatically generated list of changes in version %(version)s": "Automaatselt genereeritud nimekiri versiooni %(version)s muutustest", "C API changes": "C API muutused", "Changes in Version %(version)s — %(docstitle)s": "Muutused versioonis %(version)s — %(docstitle)s", "Collapse sidebar": "Varja k\u00fclgriba", "Complete Table of Contents": "T\u00e4ielik sisukorratabel", "Contents": "Sisukord", "Copyright": "Autori\u00f5igus", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Loodud <a href=\"http://sphinx-doc.org/\">Sphinxiga</a> (versioon: %(sphinx_version)s).", "Expand sidebar": "N\u00e4ita k\u00fclgriba", "Full index on one page": "T\u00e4isindeks \u00fchel lehel", "General Index": "\u00dcldindeks", "Global Module Index": "Globaalne moodulite indeks", "Go": "Otsi", "Hide Search Matches": "Varja otsingu tulemused", "Index": "Indeks", "Index – %(key)s": "Indeks – %(key)s", "Index pages by letter": "Indeksi lehek\u00fcljed algust\u00e4he kaupa", "Indices and tables:": "Indeksid ja tabelid:", "Last updated on %(last_updated)s.": "Viimati uuendatud %(last_updated)s.", "Library changes": "Teegi muutused", "Navigation": "Navigatsioon", "Next topic": "J\u00e4rgmine teema", "Other changes": "\u00dclej\u00e4\u00e4nud muutused", "Overview": "\u00dclevaade", "Permalink to this definition": "P\u00fcsiviit sellele definitsioonile", "Permalink to this headline": "P\u00fcsiviit sellele pealkirjale", "Please activate JavaScript to enable the search\n functionality.": "Otsingu v\u00f5imaldamiseks tuleb aktiveerida JavaScript.", "Preparing search...": "Otsingu ettevalmistamine...", "Previous topic": "Eelmine teema", "Quick search": "Kiirotsing", "Search": "Otsing", "Search Page": "Otsinguleht", "Search Results": "Otsingu tulemused", "Search finished, found %s page(s) matching the search query.": "Otsingu tulemusena leiti %s leht(e).", "Search within %(docstitle)s": "Otsi %(docstitle)s piires", "Searching": "Otsimine", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "N\u00e4ita l\u00e4htekoodi", "Table of Contents": "Sisukorratabel", "This Page": "K\u00e4esolev leht", "Welcome! This is": "Tervitused! See on", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Sinu otsingule ei vastanud \u00fckski dokument. Palun veendu, et k\u00f5ik sisestatud s\u00f5nad on \u00f5igesti kirjutatud ja sa oled valikud piisaval hulgal kategooriaid.", "all functions, classes, terms": "k\u00f5ik funktsioonid, klassid ja terminid", "can be huge": "v\u00f5ib olla v\u00e4ga suur", "last updated": "viimati uuendatud", "lists all sections and subsections": "toob v\u00e4lja k\u00f5ik sektsioonid ja alamsektsioonid", "next chapter": "j\u00e4rgmine jaotis", "previous chapter": "eelmine jaotis", "quick access to all modules": "kiire ligip\u00e4\u00e4s k\u00f5igile moodulitele", "search": "otsi", "search this documentation": "otsi sellest dokumentatsioonist", "the documentation for": "dokumentatsioon projektile"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "et", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s &8212; %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Autori\u00f5igused</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Autori\u00f5igused %(copyright)s.", + ", in ": "", + "About these documents": "Info selle dokumentatsiooni kohta", + "Automatically generated list of changes in version %(version)s": "Automaatselt genereeritud nimekiri versiooni %(version)s muutustest", + "C API changes": "C API muutused", + "Changes in Version %(version)s — %(docstitle)s": "Muutused versioonis %(version)s — %(docstitle)s", + "Collapse sidebar": "Varja k\u00fclgriba", + "Complete Table of Contents": "T\u00e4ielik sisukorratabel", + "Contents": "Sisukord", + "Copyright": "Autori\u00f5igus", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Loodud <a href=\"http://sphinx-doc.org/\">Sphinxiga</a> (versioon: %(sphinx_version)s).", + "Expand sidebar": "N\u00e4ita k\u00fclgriba", + "Full index on one page": "T\u00e4isindeks \u00fchel lehel", + "General Index": "\u00dcldindeks", + "Global Module Index": "Globaalne moodulite indeks", + "Go": "Otsi", + "Hide Search Matches": "Varja otsingu tulemused", + "Index": "Indeks", + "Index – %(key)s": "Indeks – %(key)s", + "Index pages by letter": "Indeksi lehek\u00fcljed algust\u00e4he kaupa", + "Indices and tables:": "Indeksid ja tabelid:", + "Last updated on %(last_updated)s.": "Viimati uuendatud %(last_updated)s.", + "Library changes": "Teegi muutused", + "Navigation": "Navigatsioon", + "Next topic": "J\u00e4rgmine teema", + "Other changes": "\u00dclej\u00e4\u00e4nud muutused", + "Overview": "\u00dclevaade", + "Permalink to this definition": "P\u00fcsiviit sellele definitsioonile", + "Permalink to this headline": "P\u00fcsiviit sellele pealkirjale", + "Please activate JavaScript to enable the search\n functionality.": "Otsingu v\u00f5imaldamiseks tuleb aktiveerida JavaScript.", + "Preparing search...": "Otsingu ettevalmistamine...", + "Previous topic": "Eelmine teema", + "Quick search": "Kiirotsing", + "Search": "Otsing", + "Search Page": "Otsinguleht", + "Search Results": "Otsingu tulemused", + "Search finished, found %s page(s) matching the search query.": "Otsingu tulemusena leiti %s leht(e).", + "Search within %(docstitle)s": "Otsi %(docstitle)s piires", + "Searching": "Otsimine", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "N\u00e4ita l\u00e4htekoodi", + "Table of Contents": "Sisukorratabel", + "This Page": "K\u00e4esolev leht", + "Welcome! This is": "Tervitused! See on", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Sinu otsingule ei vastanud \u00fckski dokument. Palun veendu, et k\u00f5ik sisestatud s\u00f5nad on \u00f5igesti kirjutatud ja sa oled valikud piisaval hulgal kategooriaid.", + "all functions, classes, terms": "k\u00f5ik funktsioonid, klassid ja terminid", + "can be huge": "v\u00f5ib olla v\u00e4ga suur", + "last updated": "viimati uuendatud", + "lists all sections and subsections": "toob v\u00e4lja k\u00f5ik sektsioonid ja alamsektsioonid", + "next chapter": "j\u00e4rgmine jaotis", + "previous chapter": "eelmine jaotis", + "quick access to all modules": "kiire ligip\u00e4\u00e4s k\u00f5igile moodulitele", + "search": "otsi", + "search this documentation": "otsi sellest dokumentatsioonist", + "the documentation for": "dokumentatsioon projektile" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/et/LC_MESSAGES/sphinx.po b/sphinx/locale/et/LC_MESSAGES/sphinx.po index a87de4d11..1f40f10c0 100644 --- a/sphinx/locale/et/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/et/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Aivar Annamaa <aivar.annamaa@gmail.com>, 2011 # Ivar Smolin <okul at linux ee>, 2012 diff --git a/sphinx/locale/eu/LC_MESSAGES/sphinx.js b/sphinx/locale/eu/LC_MESSAGES/sphinx.js index 9672f5d0a..65b224cdb 100644 --- a/sphinx/locale/eu/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/eu/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "eu", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "Dokumentu hauen inguruan", "Automatically generated list of changes in version %(version)s": "Automatikoki sortutako %(version)s bertsioaren aldaketen zerrenda", "C API changes": "C API aldaketak", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Alboko barra tolestu", "Complete Table of Contents": "Eduki taula osoa", "Contents": "Edukiak", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s erabiliz sortutakoa.", "Expand sidebar": "Alboko barra luzatu", "Full index on one page": "Indize guztia orri batean", "General Index": "Indize orokorra", "Global Module Index": "Modulu indize globala", "Go": "Joan", "Hide Search Matches": "Bilaketa bat-etortzeak ezkutatu", "Index": "Indizea", "Index – %(key)s": "Indizea – %(key)s", "Index pages by letter": "Indize orriak hizkika", "Indices and tables:": "Indizeak eta taulak:", "Last updated on %(last_updated)s.": "Azken aldaketa: %(last_updated)s.", "Library changes": "Liburutegi aldaketak", "Navigation": "Nabigazioa", "Next topic": "Hurrengo gaia", "Other changes": "Beste aldaketak", "Overview": "Gainbegirada", "Permalink to this definition": "Definizio honetarako esteka iraunkorra", "Permalink to this headline": "Goiburu honetarako esteka iraunkorra", "Please activate JavaScript to enable the search\n functionality.": "Mesedez, gaitu JavaScript-a bilaketa erabili ahal izateko.", "Preparing search...": "", "Previous topic": "Aurreko gaia", "Quick search": "Bilaketa azkarra", "Search": "Bilatu", "Search Page": "Bilaketa orria", "Search Results": "Bilaketa emaitzak", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "Bilatu %(docstitle)s(e)n", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Iturburua ikusi", "Table of Contents": "", "This Page": "Orri hau", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "funtzio, klase, termino guztiak", "can be huge": "handia izan daiteke", "last updated": "", "lists all sections and subsections": "atal eta azpiatal guztiak zerrendatu", "next chapter": "hurrengo kapitulua", "previous chapter": "aurreko kapitulua", "quick access to all modules": "modulu guztietara atzipen azkarra", "search": "bilatu", "search this documentation": "dokumentazio honetan bilatu", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "eu", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "Dokumentu hauen inguruan", + "Automatically generated list of changes in version %(version)s": "Automatikoki sortutako %(version)s bertsioaren aldaketen zerrenda", + "C API changes": "C API aldaketak", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Alboko barra tolestu", + "Complete Table of Contents": "Eduki taula osoa", + "Contents": "Edukiak", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s erabiliz sortutakoa.", + "Expand sidebar": "Alboko barra luzatu", + "Full index on one page": "Indize guztia orri batean", + "General Index": "Indize orokorra", + "Global Module Index": "Modulu indize globala", + "Go": "Joan", + "Hide Search Matches": "Bilaketa bat-etortzeak ezkutatu", + "Index": "Indizea", + "Index – %(key)s": "Indizea – %(key)s", + "Index pages by letter": "Indize orriak hizkika", + "Indices and tables:": "Indizeak eta taulak:", + "Last updated on %(last_updated)s.": "Azken aldaketa: %(last_updated)s.", + "Library changes": "Liburutegi aldaketak", + "Navigation": "Nabigazioa", + "Next topic": "Hurrengo gaia", + "Other changes": "Beste aldaketak", + "Overview": "Gainbegirada", + "Permalink to this definition": "Definizio honetarako esteka iraunkorra", + "Permalink to this headline": "Goiburu honetarako esteka iraunkorra", + "Please activate JavaScript to enable the search\n functionality.": "Mesedez, gaitu JavaScript-a bilaketa erabili ahal izateko.", + "Preparing search...": "", + "Previous topic": "Aurreko gaia", + "Quick search": "Bilaketa azkarra", + "Search": "Bilatu", + "Search Page": "Bilaketa orria", + "Search Results": "Bilaketa emaitzak", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "Bilatu %(docstitle)s(e)n", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Iturburua ikusi", + "Table of Contents": "", + "This Page": "Orri hau", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "funtzio, klase, termino guztiak", + "can be huge": "handia izan daiteke", + "last updated": "", + "lists all sections and subsections": "atal eta azpiatal guztiak zerrendatu", + "next chapter": "hurrengo kapitulua", + "previous chapter": "aurreko kapitulua", + "quick access to all modules": "modulu guztietara atzipen azkarra", + "search": "bilatu", + "search this documentation": "dokumentazio honetan bilatu", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/eu/LC_MESSAGES/sphinx.po b/sphinx/locale/eu/LC_MESSAGES/sphinx.po index 80dbae5a3..c6f25f8b0 100644 --- a/sphinx/locale/eu/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/eu/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Ales Zabala Alava <shagi@gisa-elkartea.org>, 2011 # Asier Iturralde Sarasola <asier.iturralde@gmail.com>, 2018 diff --git a/sphinx/locale/fa/LC_MESSAGES/sphinx.js b/sphinx/locale/fa/LC_MESSAGES/sphinx.js index 87a3025ee..fd0b2b71f 100644 --- a/sphinx/locale/fa/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/fa/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "fa", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "\u062f\u0631\u0628\u0627\u0631\u0647 \u0627\u06cc\u0646 \u0645\u0633\u062a\u0646\u062f\u0627\u062a", "Automatically generated list of changes in version %(version)s": "\u0644\u06cc\u0633\u062a \u062a\u0648\u0644\u06cc\u062f \u0634\u062f\u0647 \u062e\u0648\u062f\u06a9\u0627\u0631 \u0627\u0632 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u062f\u0631 \u0646\u0633\u062e\u0647 %(version)s", "C API changes": "C API \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "\u0641\u0647\u0631\u0633\u062a \u06a9\u0627\u0645\u0644 \u0645\u0637\u0627\u0644\u0628", "Contents": "", "Copyright": "\u06a9\u067e\u06cc \u0631\u0627\u06cc\u062a", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": ". <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u0627\u06cc\u062c\u0627\u062f \u0634\u062f\u0647 \u0628\u0627", "Expand sidebar": "", "Full index on one page": "\u0641\u0647\u0631\u0633\u062a \u06a9\u0627\u0645\u0644 \u062f\u0631 \u06cc\u06a9 \u0635\u0641\u062d\u0647", "General Index": "\u0641\u0647\u0631\u0633\u062a \u06a9\u0644\u06cc", "Global Module Index": "\u0641\u0647\u0631\u0633\u062a \u06a9\u0644\u06cc \u0645\u0627\u0698\u0648\u0644 \u0647\u0627", "Go": "\u0628\u0631\u0648", "Hide Search Matches": "\u0639\u062f\u0645 \u0646\u0645\u0627\u06cc\u0634 \u0646\u062a\u0627\u06cc\u062c \u06cc\u0627\u0641\u062a \u0634\u062f\u0647", "Index": "\u0641\u0647\u0631\u0633\u062a", "Index – %(key)s": "\u0641\u0647\u0631\u0633\u062a – %(key)s", "Index pages by letter": "\u0641\u0647\u0631\u0633\u062a \u0635\u0641\u062d\u0627\u062a \u0628\u0631 \u0627\u0633\u0627\u0633 \u062d\u0631\u0648\u0641", "Indices and tables:": "\u0627\u06cc\u0646\u062f\u06a9\u0633 \u0647\u0627 \u0648 \u062c\u062f\u0627\u0648\u0644:", "Last updated on %(last_updated)s.": ". %(last_updated)s \u0622\u062e\u0631\u06cc\u0646 \u0628\u0631\u0648\u0632 \u0631\u0633\u0627\u0646\u06cc \u062f\u0631", "Library changes": "\u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u06a9\u062a\u0627\u0628\u062e\u0627\u0646\u0647 \u0627\u06cc\u06cc", "Navigation": "\u0646\u0627\u0648\u0628\u0631\u06cc", "Next topic": "\u0645\u0648\u0636\u0648\u0639 \u0628\u0639\u062f\u06cc", "Other changes": "\u062f\u06af\u0631 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a", "Overview": "\u0628\u0631\u0631\u0633\u06cc \u0627\u062c\u0645\u0627\u0644\u06cc", "Permalink to this definition": "\u0644\u06cc\u0646\u06a9 \u062b\u0627\u0628\u062a \u0628\u0647 \u0627\u06cc\u0646 \u062a\u0639\u0631\u06cc\u0641", "Permalink to this headline": "\u0644\u06cc\u0646\u06a9 \u062b\u0627\u0628\u062a \u0628\u0647 \u0627\u06cc\u0646 \u0633\u0631 \u0645\u0642\u0627\u0644\u0647", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "\u0645\u0648\u0636\u0648\u0639 \u0642\u0628\u0644\u06cc", "Quick search": "\u062c\u0633\u062a\u062c\u0648 \u0633\u0631\u06cc\u0639", "Search": "\u062c\u0633\u062a\u062c\u0648", "Search Page": "\u0635\u0641\u062d\u0647 \u062c\u0633\u062a\u062c\u0648", "Search Results": "\u0646\u062a\u0627\u06cc\u062c \u062c\u0633\u062a\u062c\u0648", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "\u062c\u0633\u062a\u062c\u0648 \u062f\u0631 %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u0646\u0645\u0627\u06cc\u0634 \u0633\u0648\u0631\u0633", "Table of Contents": "", "This Page": "\u0635\u0641\u062d\u0647 \u0641\u0639\u0644\u06cc", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "\u062a\u0645\u0627\u0645\u06cc \u062a\u0648\u0627\u0628\u0639 \u060c \u06a9\u0644\u0627\u0633 \u0647\u0627 \u060c \u0627\u0635\u0637\u0644\u0627\u062d\u0627\u062a", "can be huge": "", "last updated": "", "lists all sections and subsections": "\u0641\u0647\u0631\u0633\u062a \u062a\u0645\u0627\u0645\u06cc \u0628\u062e\u0634 \u0647\u0627 \u0648 \u0632\u06cc\u0631 \u0645\u062c\u0645\u0648\u0639\u0647 \u0647\u0627", "next chapter": "\u0641\u0635\u0644 \u0628\u0639\u062f\u06cc", "previous chapter": "\u0641\u0635\u0644 \u0642\u0628\u0644\u06cc", "quick access to all modules": "\u062f\u0633\u062a\u0631\u0633\u06cc \u0633\u0631\u06cc\u0639 \u0628\u0647 \u062a\u0645\u0627\u0645\u06cc \u0645\u062a\u062f\u0647\u0627", "search": "\u062c\u0633\u062a\u062c\u0648", "search this documentation": "\u062c\u0633\u062a\u062c\u0648 \u062f\u0631 \u0627\u06cc\u0646 \u0627\u0633\u0646\u0627\u062f", "the documentation for": ""}, "plural_expr": "(n > 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "fa", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "\u062f\u0631\u0628\u0627\u0631\u0647 \u0627\u06cc\u0646 \u0645\u0633\u062a\u0646\u062f\u0627\u062a", + "Automatically generated list of changes in version %(version)s": "\u0644\u06cc\u0633\u062a \u062a\u0648\u0644\u06cc\u062f \u0634\u062f\u0647 \u062e\u0648\u062f\u06a9\u0627\u0631 \u0627\u0632 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u062f\u0631 \u0646\u0633\u062e\u0647 %(version)s", + "C API changes": "C API \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "\u0641\u0647\u0631\u0633\u062a \u06a9\u0627\u0645\u0644 \u0645\u0637\u0627\u0644\u0628", + "Contents": "", + "Copyright": "\u06a9\u067e\u06cc \u0631\u0627\u06cc\u062a", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": ". <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u0627\u06cc\u062c\u0627\u062f \u0634\u062f\u0647 \u0628\u0627", + "Expand sidebar": "", + "Full index on one page": "\u0641\u0647\u0631\u0633\u062a \u06a9\u0627\u0645\u0644 \u062f\u0631 \u06cc\u06a9 \u0635\u0641\u062d\u0647", + "General Index": "\u0641\u0647\u0631\u0633\u062a \u06a9\u0644\u06cc", + "Global Module Index": "\u0641\u0647\u0631\u0633\u062a \u06a9\u0644\u06cc \u0645\u0627\u0698\u0648\u0644 \u0647\u0627", + "Go": "\u0628\u0631\u0648", + "Hide Search Matches": "\u0639\u062f\u0645 \u0646\u0645\u0627\u06cc\u0634 \u0646\u062a\u0627\u06cc\u062c \u06cc\u0627\u0641\u062a \u0634\u062f\u0647", + "Index": "\u0641\u0647\u0631\u0633\u062a", + "Index – %(key)s": "\u0641\u0647\u0631\u0633\u062a – %(key)s", + "Index pages by letter": "\u0641\u0647\u0631\u0633\u062a \u0635\u0641\u062d\u0627\u062a \u0628\u0631 \u0627\u0633\u0627\u0633 \u062d\u0631\u0648\u0641", + "Indices and tables:": "\u0627\u06cc\u0646\u062f\u06a9\u0633 \u0647\u0627 \u0648 \u062c\u062f\u0627\u0648\u0644:", + "Last updated on %(last_updated)s.": ". %(last_updated)s \u0622\u062e\u0631\u06cc\u0646 \u0628\u0631\u0648\u0632 \u0631\u0633\u0627\u0646\u06cc \u062f\u0631", + "Library changes": "\u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u06a9\u062a\u0627\u0628\u062e\u0627\u0646\u0647 \u0627\u06cc\u06cc", + "Navigation": "\u0646\u0627\u0648\u0628\u0631\u06cc", + "Next topic": "\u0645\u0648\u0636\u0648\u0639 \u0628\u0639\u062f\u06cc", + "Other changes": "\u062f\u06af\u0631 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a", + "Overview": "\u0628\u0631\u0631\u0633\u06cc \u0627\u062c\u0645\u0627\u0644\u06cc", + "Permalink to this definition": "\u0644\u06cc\u0646\u06a9 \u062b\u0627\u0628\u062a \u0628\u0647 \u0627\u06cc\u0646 \u062a\u0639\u0631\u06cc\u0641", + "Permalink to this headline": "\u0644\u06cc\u0646\u06a9 \u062b\u0627\u0628\u062a \u0628\u0647 \u0627\u06cc\u0646 \u0633\u0631 \u0645\u0642\u0627\u0644\u0647", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "\u0645\u0648\u0636\u0648\u0639 \u0642\u0628\u0644\u06cc", + "Quick search": "\u062c\u0633\u062a\u062c\u0648 \u0633\u0631\u06cc\u0639", + "Search": "\u062c\u0633\u062a\u062c\u0648", + "Search Page": "\u0635\u0641\u062d\u0647 \u062c\u0633\u062a\u062c\u0648", + "Search Results": "\u0646\u062a\u0627\u06cc\u062c \u062c\u0633\u062a\u062c\u0648", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "\u062c\u0633\u062a\u062c\u0648 \u062f\u0631 %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u0646\u0645\u0627\u06cc\u0634 \u0633\u0648\u0631\u0633", + "Table of Contents": "", + "This Page": "\u0635\u0641\u062d\u0647 \u0641\u0639\u0644\u06cc", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "\u062a\u0645\u0627\u0645\u06cc \u062a\u0648\u0627\u0628\u0639 \u060c \u06a9\u0644\u0627\u0633 \u0647\u0627 \u060c \u0627\u0635\u0637\u0644\u0627\u062d\u0627\u062a", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "\u0641\u0647\u0631\u0633\u062a \u062a\u0645\u0627\u0645\u06cc \u0628\u062e\u0634 \u0647\u0627 \u0648 \u0632\u06cc\u0631 \u0645\u062c\u0645\u0648\u0639\u0647 \u0647\u0627", + "next chapter": "\u0641\u0635\u0644 \u0628\u0639\u062f\u06cc", + "previous chapter": "\u0641\u0635\u0644 \u0642\u0628\u0644\u06cc", + "quick access to all modules": "\u062f\u0633\u062a\u0631\u0633\u06cc \u0633\u0631\u06cc\u0639 \u0628\u0647 \u062a\u0645\u0627\u0645\u06cc \u0645\u062a\u062f\u0647\u0627", + "search": "\u062c\u0633\u062a\u062c\u0648", + "search this documentation": "\u062c\u0633\u062a\u062c\u0648 \u062f\u0631 \u0627\u06cc\u0646 \u0627\u0633\u0646\u0627\u062f", + "the documentation for": "" + }, + "plural_expr": "(n > 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/fa/LC_MESSAGES/sphinx.po b/sphinx/locale/fa/LC_MESSAGES/sphinx.po index ddca8112c..066cfc4bb 100644 --- a/sphinx/locale/fa/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/fa/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/fi/LC_MESSAGES/sphinx.js b/sphinx/locale/fi/LC_MESSAGES/sphinx.js index 1c2906863..bda0d7943 100644 --- a/sphinx/locale/fi/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/fi/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "fi", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "Tietoja t\u00e4st\u00e4 documentist\u00e4", "Automatically generated list of changes in version %(version)s": "Automaattisesti luotu muutoshistoria alkaen versiosta %(version)s", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "Hakemisto yhten\u00e4 luettelona", "General Index": "Yleinen sis\u00e4llysluettelo", "Global Module Index": "Yleinen moduulien sis\u00e4llysluettelo", "Go": "Siirry", "Hide Search Matches": "Piilota l\u00f6ydetyt", "Index": "Sis\u00e4llysluettelo", "Index – %(key)s": "", "Index pages by letter": "Hakemisto aakkostus sivuttain", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "Navikointi", "Next topic": ">>", "Other changes": "", "Overview": "Yhteenveto", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "Javascript pit\u00e4\u00e4 olla sallittu, jotta etsint\u00e4 toimii.", "Preparing search...": "", "Previous topic": "<<", "Quick search": "Pikahaku", "Search": "Etsi", "Search Page": "Etsi sivu", "Search Results": "Etsinn\u00e4n tulos", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "N\u00e4yt\u00e4 l\u00e4hdekoodina", "Table of Contents": "", "This Page": "T\u00e4m\u00e4 sivu", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "voi olla iso", "last updated": "", "lists all sections and subsections": "", "next chapter": ">>", "previous chapter": "<<", "quick access to all modules": "", "search": "etsi", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "fi", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "Tietoja t\u00e4st\u00e4 documentist\u00e4", + "Automatically generated list of changes in version %(version)s": "Automaattisesti luotu muutoshistoria alkaen versiosta %(version)s", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "Hakemisto yhten\u00e4 luettelona", + "General Index": "Yleinen sis\u00e4llysluettelo", + "Global Module Index": "Yleinen moduulien sis\u00e4llysluettelo", + "Go": "Siirry", + "Hide Search Matches": "Piilota l\u00f6ydetyt", + "Index": "Sis\u00e4llysluettelo", + "Index – %(key)s": "", + "Index pages by letter": "Hakemisto aakkostus sivuttain", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "Navikointi", + "Next topic": ">>", + "Other changes": "", + "Overview": "Yhteenveto", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "Javascript pit\u00e4\u00e4 olla sallittu, jotta etsint\u00e4 toimii.", + "Preparing search...": "", + "Previous topic": "<<", + "Quick search": "Pikahaku", + "Search": "Etsi", + "Search Page": "Etsi sivu", + "Search Results": "Etsinn\u00e4n tulos", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "N\u00e4yt\u00e4 l\u00e4hdekoodina", + "Table of Contents": "", + "This Page": "T\u00e4m\u00e4 sivu", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "voi olla iso", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": ">>", + "previous chapter": "<<", + "quick access to all modules": "", + "search": "etsi", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/fi/LC_MESSAGES/sphinx.po b/sphinx/locale/fi/LC_MESSAGES/sphinx.po index 19233894d..6e18d601a 100644 --- a/sphinx/locale/fi/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/fi/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2009 msgid "" diff --git a/sphinx/locale/fr/LC_MESSAGES/sphinx.js b/sphinx/locale/fr/LC_MESSAGES/sphinx.js index af036d670..d22a05069 100644 --- a/sphinx/locale/fr/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/fr/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "fr", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", dans", "About these documents": "\u00c0 propos de ces documents", "Automatically generated list of changes in version %(version)s": "Liste auto-g\u00e9n\u00e9r\u00e9e des modifications dans la version %(version)s", "C API changes": "Modifications de l'API C", "Changes in Version %(version)s — %(docstitle)s": "Changements dans la version %(version)s — %(docstitle)s", "Collapse sidebar": "R\u00e9duire la barre lat\u00e9rale", "Complete Table of Contents": "Table des mati\u00e8res compl\u00e8te", "Contents": "Contenu", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Cr\u00e9\u00e9 avec <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Agrandir la barre lat\u00e9rale", "Full index on one page": "Index complet sur une seule page", "General Index": "Index g\u00e9n\u00e9ral", "Global Module Index": "Index g\u00e9n\u00e9ral des modules", "Go": "Go", "Hide Search Matches": "Cacher les r\u00e9sultats de la recherche", "Index": "Index", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "Indexer les pages par lettre", "Indices and tables:": "Indices et tables :", "Last updated on %(last_updated)s.": "Mis \u00e0 jour le %(last_updated)s.", "Library changes": "Modifications de la biblioth\u00e8que", "Navigation": "Navigation", "Next topic": "Sujet suivant", "Other changes": "Autres modifications", "Overview": "R\u00e9sum\u00e9", "Permalink to this definition": "Lien permanent vers cette d\u00e9finition", "Permalink to this headline": "Lien permanent vers ce titre", "Please activate JavaScript to enable the search\n functionality.": "Veuillez activer le JavaScript pour que la recherche fonctionne.", "Preparing search...": "Pr\u00e9paration de la recherche...", "Previous topic": "Sujet pr\u00e9c\u00e9dent", "Quick search": "Recherche rapide", "Search": "Recherche", "Search Page": "Page de recherche", "Search Results": "R\u00e9sultats de la recherche", "Search finished, found %s page(s) matching the search query.": "La recherche est finie, %s page(s) trouv\u00e9e(s) qui corresponde(nt) \u00e0 la recherche.", "Search within %(docstitle)s": "Recherchez dans %(docstitle)s", "Searching": "Recherche en cours", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Montrer le code source", "Table of Contents": "Table des mati\u00e8res", "This Page": "Cette page", "Welcome! This is": "Bienvenue ! Ceci est", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Votre recherche ne correspond \u00e0 aucun document. Veuillez v\u00e9rifier que les mots sont correctement orthographi\u00e9s et que vous avez s\u00e9lectionn\u00e9 assez de cat\u00e9gories.", "all functions, classes, terms": "toutes les fonctions, classes, termes", "can be huge": "peut \u00eatre \u00e9norme", "last updated": "derni\u00e8re modification", "lists all sections and subsections": "lister l'ensemble des sections et sous-sections", "next chapter": "Chapitre suivant", "previous chapter": "Chapitre pr\u00e9c\u00e9dent", "quick access to all modules": "acc\u00e8s rapide \u00e0 l'ensemble des modules", "search": "rechercher", "search this documentation": "rechercher dans cette documentation", "the documentation for": "la documentation pour"}, "plural_expr": "(n > 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "fr", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", dans", + "About these documents": "\u00c0 propos de ces documents", + "Automatically generated list of changes in version %(version)s": "Liste auto-g\u00e9n\u00e9r\u00e9e des modifications dans la version %(version)s", + "C API changes": "Modifications de l'API C", + "Changes in Version %(version)s — %(docstitle)s": "Changements dans la version %(version)s — %(docstitle)s", + "Collapse sidebar": "R\u00e9duire la barre lat\u00e9rale", + "Complete Table of Contents": "Table des mati\u00e8res compl\u00e8te", + "Contents": "Contenu", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Cr\u00e9\u00e9 avec <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Agrandir la barre lat\u00e9rale", + "Full index on one page": "Index complet sur une seule page", + "General Index": "Index g\u00e9n\u00e9ral", + "Global Module Index": "Index g\u00e9n\u00e9ral des modules", + "Go": "Go", + "Hide Search Matches": "Cacher les r\u00e9sultats de la recherche", + "Index": "Index", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "Indexer les pages par lettre", + "Indices and tables:": "Indices et tables :", + "Last updated on %(last_updated)s.": "Mis \u00e0 jour le %(last_updated)s.", + "Library changes": "Modifications de la biblioth\u00e8que", + "Navigation": "Navigation", + "Next topic": "Sujet suivant", + "Other changes": "Autres modifications", + "Overview": "R\u00e9sum\u00e9", + "Permalink to this definition": "Lien permanent vers cette d\u00e9finition", + "Permalink to this headline": "Lien permanent vers ce titre", + "Please activate JavaScript to enable the search\n functionality.": "Veuillez activer le JavaScript pour que la recherche fonctionne.", + "Preparing search...": "Pr\u00e9paration de la recherche...", + "Previous topic": "Sujet pr\u00e9c\u00e9dent", + "Quick search": "Recherche rapide", + "Search": "Recherche", + "Search Page": "Page de recherche", + "Search Results": "R\u00e9sultats de la recherche", + "Search finished, found %s page(s) matching the search query.": "La recherche est finie, %s page(s) trouv\u00e9e(s) qui corresponde(nt) \u00e0 la recherche.", + "Search within %(docstitle)s": "Recherchez dans %(docstitle)s", + "Searching": "Recherche en cours", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Montrer le code source", + "Table of Contents": "Table des mati\u00e8res", + "This Page": "Cette page", + "Welcome! This is": "Bienvenue ! Ceci est", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Votre recherche ne correspond \u00e0 aucun document. Veuillez v\u00e9rifier que les mots sont correctement orthographi\u00e9s et que vous avez s\u00e9lectionn\u00e9 assez de cat\u00e9gories.", + "all functions, classes, terms": "toutes les fonctions, classes, termes", + "can be huge": "peut \u00eatre \u00e9norme", + "last updated": "derni\u00e8re modification", + "lists all sections and subsections": "lister l'ensemble des sections et sous-sections", + "next chapter": "Chapitre suivant", + "previous chapter": "Chapitre pr\u00e9c\u00e9dent", + "quick access to all modules": "acc\u00e8s rapide \u00e0 l'ensemble des modules", + "search": "rechercher", + "search this documentation": "rechercher dans cette documentation", + "the documentation for": "la documentation pour" + }, + "plural_expr": "(n > 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/fr/LC_MESSAGES/sphinx.po b/sphinx/locale/fr/LC_MESSAGES/sphinx.po index b01d956c0..740e9ba70 100644 --- a/sphinx/locale/fr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/fr/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Christophe CHAUVET <christophe.chauvet@gmail.com>, 2017 # Christophe CHAUVET <christophe.chauvet@gmail.com>, 2013,2015 diff --git a/sphinx/locale/he/LC_MESSAGES/sphinx.js b/sphinx/locale/he/LC_MESSAGES/sphinx.js index bda8b13d0..bf11f383e 100644 --- a/sphinx/locale/he/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/he/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "he", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "\u05e2\u05dc \u05de\u05e1\u05de\u05db\u05d9\u05dd \u05d0\u05dc\u05d5", "Automatically generated list of changes in version %(version)s": "\u05d9\u05e6\u05e8 \u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9\u05ea \u05e8\u05e9\u05d9\u05de\u05d4 \u05e9\u05dc \u05e9\u05d9\u05e0\u05d5\u05d9\u05d9\u05dd \u05d1\u05d2\u05e8\u05e1\u05d4 %(version)s", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "\u05db\u05d5\u05d5\u05e5 \u05e1\u05e8\u05d2\u05dc \u05e6\u05d3", "Complete Table of Contents": "\u05ea\u05d5\u05db\u05df \u05e2\u05e0\u05d9\u05d9\u05e0\u05d9\u05dd \u05de\u05dc\u05d0", "Contents": "\u05ea\u05d5\u05db\u05df", "Copyright": "\u05d6\u05db\u05d5\u05d9\u05d5\u05ea \u05e9\u05de\u05d5\u05e8\u05d5\u05ea", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "\u05d4\u05e8\u05d7\u05d1 \u05e1\u05e8\u05d2\u05dc \u05e6\u05d3", "Full index on one page": "\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1 \u05de\u05dc\u05d0 \u05d1\u05e2\u05de\u05d5\u05d3 \u05d0\u05d7\u05d3", "General Index": "", "Global Module Index": "\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1 \u05de\u05d5\u05d3\u05d5\u05dc\u05d9\u05dd \u05d2\u05dc\u05d5\u05d1\u05dc\u05d9", "Go": "\u05dc\u05da", "Hide Search Matches": "\u05d4\u05e1\u05ea\u05e8 \u05ea\u05d5\u05e6\u05d0\u05d5\u05ea \u05d7\u05d9\u05e4\u05d5\u05e9", "Index": "\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1", "Index – %(key)s": "", "Index pages by letter": "\u05e2\u05de\u05d5\u05d3\u05d9 \u05d0\u05d9\u05e0\u05d3\u05e7\u05e1 \u05dc\u05e4\u05d9 \u05d0\u05d5\u05ea\u05d9\u05d5\u05ea", "Indices and tables:": "", "Last updated on %(last_updated)s.": "\u05e2\u05d5\u05d3\u05db\u05df \u05dc\u05d0\u05d7\u05e8\u05d5\u05e0\u05d4 \u05d1 %(last_updated)s.", "Library changes": "", "Navigation": "\u05e0\u05d9\u05d5\u05d5\u05d8", "Next topic": "\u05e0\u05d5\u05e9\u05d0 \u05d4\u05d1\u05d0", "Other changes": "\u05e9\u05d9\u05e0\u05d5\u05d9\u05d9\u05dd \u05d0\u05d7\u05e8\u05d9\u05dd", "Overview": "\u05e1\u05e7\u05d9\u05e8\u05d4 \u05db\u05dc\u05dc\u05d9\u05ea", "Permalink to this definition": "\u05e7\u05d9\u05e9\u05d5\u05e8 \u05e7\u05d1\u05d5\u05e2 \u05dc\u05d4\u05d2\u05d3\u05e8\u05d4 \u05d6\u05d5", "Permalink to this headline": "\u05e7\u05d9\u05e9\u05d5\u05e8 \u05e7\u05d1\u05d5\u05e2 \u05dc\u05db\u05d5\u05ea\u05e8\u05ea \u05d6\u05d5", "Please activate JavaScript to enable the search\n functionality.": "\u05d0\u05e0\u05d0 \u05d4\u05e4\u05e2\u05dc \u05d2'\u05d0\u05d5\u05d0\u05e1\u05e7\u05e8\u05d9\u05e4\u05d8 \u05e2\"\u05de \u05dc\u05d0\u05e4\u05e9\u05e8 \u05d0\u05ea\n \u05d4\u05d7\u05d9\u05e4\u05d5\u05e9.", "Preparing search...": "", "Previous topic": "\u05e0\u05d5\u05e9\u05d0 \u05e7\u05d5\u05d3\u05dd", "Quick search": "\u05d7\u05d9\u05e4\u05d5\u05e9 \u05de\u05d4\u05d9\u05e8", "Search": "\u05d7\u05d9\u05e4\u05d5\u05e9", "Search Page": "\u05d3\u05e3 \u05d7\u05d9\u05e4\u05d5\u05e9", "Search Results": "\u05ea\u05d5\u05e6\u05d0\u05d5\u05ea \u05d4\u05d7\u05d9\u05e4\u05d5\u05e9", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "\u05d7\u05e4\u05e9 \u05d1\u05ea\u05d5\u05da %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u05d4\u05e6\u05d2 \u05de\u05e7\u05d5\u05e8", "Table of Contents": "", "This Page": "\u05e2\u05de\u05d5\u05d3 \u05d6\u05d4", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "\u05db\u05dc \u05d4\u05e4\u05d5\u05e0\u05e7\u05e6\u05d9\u05d5\u05ea, \u05d4\u05de\u05d7\u05dc\u05e7\u05d5\u05ea, \u05d4\u05de\u05d5\u05e9\u05d2\u05d9\u05dd", "can be huge": "\u05e2\u05e9\u05d5\u05d9 \u05dc\u05d4\u05d9\u05d5\u05ea \u05e2\u05e6\u05d5\u05dd", "last updated": "", "lists all sections and subsections": "", "next chapter": "\u05e4\u05e8\u05e7 \u05d4\u05d1\u05d0", "previous chapter": "\u05e4\u05e8\u05e7 \u05e7\u05d5\u05d3\u05dd", "quick access to all modules": "\u05d2\u05d9\u05e9\u05d4 \u05de\u05d4\u05d9\u05e8\u05d4 \u05dc\u05db\u05dc \u05d4\u05de\u05d5\u05d3\u05d5\u05dc\u05d9\u05dd", "search": "\u05d7\u05d9\u05e4\u05d5\u05e9", "search this documentation": "\u05d7\u05e4\u05e9 \u05d1\u05ea\u05d9\u05e2\u05d5\u05d3 \u05d6\u05d4", "the documentation for": ""}, "plural_expr": "(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "he", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "\u05e2\u05dc \u05de\u05e1\u05de\u05db\u05d9\u05dd \u05d0\u05dc\u05d5", + "Automatically generated list of changes in version %(version)s": "\u05d9\u05e6\u05e8 \u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9\u05ea \u05e8\u05e9\u05d9\u05de\u05d4 \u05e9\u05dc \u05e9\u05d9\u05e0\u05d5\u05d9\u05d9\u05dd \u05d1\u05d2\u05e8\u05e1\u05d4 %(version)s", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "\u05db\u05d5\u05d5\u05e5 \u05e1\u05e8\u05d2\u05dc \u05e6\u05d3", + "Complete Table of Contents": "\u05ea\u05d5\u05db\u05df \u05e2\u05e0\u05d9\u05d9\u05e0\u05d9\u05dd \u05de\u05dc\u05d0", + "Contents": "\u05ea\u05d5\u05db\u05df", + "Copyright": "\u05d6\u05db\u05d5\u05d9\u05d5\u05ea \u05e9\u05de\u05d5\u05e8\u05d5\u05ea", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "\u05d4\u05e8\u05d7\u05d1 \u05e1\u05e8\u05d2\u05dc \u05e6\u05d3", + "Full index on one page": "\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1 \u05de\u05dc\u05d0 \u05d1\u05e2\u05de\u05d5\u05d3 \u05d0\u05d7\u05d3", + "General Index": "", + "Global Module Index": "\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1 \u05de\u05d5\u05d3\u05d5\u05dc\u05d9\u05dd \u05d2\u05dc\u05d5\u05d1\u05dc\u05d9", + "Go": "\u05dc\u05da", + "Hide Search Matches": "\u05d4\u05e1\u05ea\u05e8 \u05ea\u05d5\u05e6\u05d0\u05d5\u05ea \u05d7\u05d9\u05e4\u05d5\u05e9", + "Index": "\u05d0\u05d9\u05e0\u05d3\u05e7\u05e1", + "Index – %(key)s": "", + "Index pages by letter": "\u05e2\u05de\u05d5\u05d3\u05d9 \u05d0\u05d9\u05e0\u05d3\u05e7\u05e1 \u05dc\u05e4\u05d9 \u05d0\u05d5\u05ea\u05d9\u05d5\u05ea", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "\u05e2\u05d5\u05d3\u05db\u05df \u05dc\u05d0\u05d7\u05e8\u05d5\u05e0\u05d4 \u05d1 %(last_updated)s.", + "Library changes": "", + "Navigation": "\u05e0\u05d9\u05d5\u05d5\u05d8", + "Next topic": "\u05e0\u05d5\u05e9\u05d0 \u05d4\u05d1\u05d0", + "Other changes": "\u05e9\u05d9\u05e0\u05d5\u05d9\u05d9\u05dd \u05d0\u05d7\u05e8\u05d9\u05dd", + "Overview": "\u05e1\u05e7\u05d9\u05e8\u05d4 \u05db\u05dc\u05dc\u05d9\u05ea", + "Permalink to this definition": "\u05e7\u05d9\u05e9\u05d5\u05e8 \u05e7\u05d1\u05d5\u05e2 \u05dc\u05d4\u05d2\u05d3\u05e8\u05d4 \u05d6\u05d5", + "Permalink to this headline": "\u05e7\u05d9\u05e9\u05d5\u05e8 \u05e7\u05d1\u05d5\u05e2 \u05dc\u05db\u05d5\u05ea\u05e8\u05ea \u05d6\u05d5", + "Please activate JavaScript to enable the search\n functionality.": "\u05d0\u05e0\u05d0 \u05d4\u05e4\u05e2\u05dc \u05d2'\u05d0\u05d5\u05d0\u05e1\u05e7\u05e8\u05d9\u05e4\u05d8 \u05e2\"\u05de \u05dc\u05d0\u05e4\u05e9\u05e8 \u05d0\u05ea\n \u05d4\u05d7\u05d9\u05e4\u05d5\u05e9.", + "Preparing search...": "", + "Previous topic": "\u05e0\u05d5\u05e9\u05d0 \u05e7\u05d5\u05d3\u05dd", + "Quick search": "\u05d7\u05d9\u05e4\u05d5\u05e9 \u05de\u05d4\u05d9\u05e8", + "Search": "\u05d7\u05d9\u05e4\u05d5\u05e9", + "Search Page": "\u05d3\u05e3 \u05d7\u05d9\u05e4\u05d5\u05e9", + "Search Results": "\u05ea\u05d5\u05e6\u05d0\u05d5\u05ea \u05d4\u05d7\u05d9\u05e4\u05d5\u05e9", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "\u05d7\u05e4\u05e9 \u05d1\u05ea\u05d5\u05da %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u05d4\u05e6\u05d2 \u05de\u05e7\u05d5\u05e8", + "Table of Contents": "", + "This Page": "\u05e2\u05de\u05d5\u05d3 \u05d6\u05d4", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "\u05db\u05dc \u05d4\u05e4\u05d5\u05e0\u05e7\u05e6\u05d9\u05d5\u05ea, \u05d4\u05de\u05d7\u05dc\u05e7\u05d5\u05ea, \u05d4\u05de\u05d5\u05e9\u05d2\u05d9\u05dd", + "can be huge": "\u05e2\u05e9\u05d5\u05d9 \u05dc\u05d4\u05d9\u05d5\u05ea \u05e2\u05e6\u05d5\u05dd", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "\u05e4\u05e8\u05e7 \u05d4\u05d1\u05d0", + "previous chapter": "\u05e4\u05e8\u05e7 \u05e7\u05d5\u05d3\u05dd", + "quick access to all modules": "\u05d2\u05d9\u05e9\u05d4 \u05de\u05d4\u05d9\u05e8\u05d4 \u05dc\u05db\u05dc \u05d4\u05de\u05d5\u05d3\u05d5\u05dc\u05d9\u05dd", + "search": "\u05d7\u05d9\u05e4\u05d5\u05e9", + "search this documentation": "\u05d7\u05e4\u05e9 \u05d1\u05ea\u05d9\u05e2\u05d5\u05d3 \u05d6\u05d4", + "the documentation for": "" + }, + "plural_expr": "(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3" +});
\ No newline at end of file diff --git a/sphinx/locale/he/LC_MESSAGES/sphinx.po b/sphinx/locale/he/LC_MESSAGES/sphinx.po index 7332af27f..1f8d45480 100644 --- a/sphinx/locale/he/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/he/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2011 msgid "" diff --git a/sphinx/locale/hi/LC_MESSAGES/sphinx.js b/sphinx/locale/hi/LC_MESSAGES/sphinx.js index 43c4e21fb..f33f44faa 100644 --- a/sphinx/locale/hi/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/hi/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "hi", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">\u0938\u0930\u094d\u0935\u093e\u0927\u093f\u0915\u093e\u0930</a> %(copyright)s.", "© Copyright %(copyright)s.": "© \u0938\u0930\u094d\u0935\u093e\u0927\u093f\u0915\u093e\u0930 %(copyright)s.", ", in ": ", \u092e\u0947\u0902 ", "About these documents": "\u0907\u0928 \u0932\u0947\u0916\u092a\u0924\u094d\u0930\u094b\u0902 \u0915\u0947 \u092c\u093e\u0930\u0947 \u092e\u0947\u0902", "Automatically generated list of changes in version %(version)s": "\u0938\u0902\u0938\u094d\u0915\u0930\u0923 %(version)s \u092e\u0947\u0902 \u0938\u094d\u0935\u0924\u0903 \u0930\u091a\u093f\u0924 \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928\u094b\u0902 \u0915\u0940 \u0938\u0942\u091a\u0940", "C API changes": "\u0938\u0940 \u0910.\u092a\u0940.\u0906\u0908. \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928", "Changes in Version %(version)s — %(docstitle)s": "\u092a\u0930\u093f\u0935\u0930\u094d\u0924\u093f\u0924 \u0938\u0902\u0938\u094d\u0915\u0930\u0923 %(version)s — %(docstitle)s", "Collapse sidebar": "\u0915\u093f\u0928\u093e\u0930\u0947 \u0915\u093e \u0938\u094d\u0925\u093e\u0928 \u0918\u091f\u093e\u090f\u0902", "Complete Table of Contents": "\u0935\u093f\u0938\u094d\u0924\u0943\u0924 \u0935\u093f\u0937\u092f-\u0938\u0942\u091a\u0940", "Contents": "\u0935\u093f\u0937\u092f \u0938\u093e\u092e\u093f\u0917\u094d\u0930\u0940", "Copyright": "\u0938\u0930\u094d\u0935\u093e\u0927\u093f\u0915\u093e\u0930", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u0938\u0947 \u0928\u093f\u0930\u094d\u092e\u093f\u0924.", "Expand sidebar": "\u0915\u093f\u0928\u093e\u0930\u0947 \u0915\u093e \u0938\u094d\u0925\u093e\u0928 \u092c\u095d\u093e\u090f\u0902", "Full index on one page": "\u090f\u0915 \u092a\u0943\u0937\u094d\u0920 \u092a\u0930 \u092a\u0942\u0930\u0940 \u0905\u0928\u0941\u0915\u094d\u0930\u092e\u0923\u093f\u0915\u093e", "General Index": "\u0938\u093e\u092e\u093e\u0928\u094d\u092f \u0905\u0928\u0941\u0915\u094d\u0930\u092e\u093e\u0923\u093f\u0915\u093e", "Global Module Index": "\u0938\u093e\u0930\u094d\u0935\u092d\u094c\u092e\u093f\u0915 \u092a\u094d\u0930\u092d\u093e\u0917 \u0938\u0942\u091a\u0940", "Go": "\u091a\u0932\u093f\u090f", "Hide Search Matches": "\u0916\u094b\u091c\u0947 \u0917\u090f \u091c\u094b\u095c\u0947 \u091b\u093f\u092a\u093e\u090f\u0902", "Index": "\u0905\u0928\u0941\u0915\u094d\u0930\u092e\u0923\u093f\u0915\u093e", "Index – %(key)s": "\u0905\u0928\u0941\u0915\u094d\u0930\u092e\u0923\u093f\u0915\u093e – %(key)s", "Index pages by letter": "\u0905\u0915\u094d\u0937\u0930 \u0926\u094d\u0935\u093e\u0930\u093e \u0905\u0928\u0941\u0915\u094d\u0930\u092e\u093f\u0924 \u092a\u0943\u0937\u094d\u0920", "Indices and tables:": "\u0938\u0942\u091a\u093f\u092f\u093e\u0901 \u0914\u0930 \u0938\u093e\u0930\u0923\u093f\u092f\u093e\u0901:", "Last updated on %(last_updated)s.": "\u0905\u0902\u0924\u093f\u092e \u092c\u093e\u0930 \u0938\u092e\u094d\u092a\u093e\u0926\u093f\u0924 %(last_updated)s.", "Library changes": "\u092a\u0941\u0938\u094d\u0924\u0915\u093e\u0932\u092f \u092e\u0947\u0902 \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928", "Navigation": "\u0938\u0902\u091a\u093e\u0932\u0928", "Next topic": "\u0905\u0917\u0932\u093e \u092a\u094d\u0930\u0915\u0930\u0923", "Other changes": "\u0905\u0928\u094d\u092f \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928", "Overview": "\u0938\u093f\u0902\u0939\u093e\u0935\u0932\u094b\u0915\u0928", "Permalink to this definition": "\u0907\u0938 \u092a\u0930\u093f\u092d\u093e\u0937\u093e \u0915\u0940 \u0938\u094d\u0925\u093e\u092f\u0940 \u0915\u095c\u0940", "Permalink to this headline": "\u0907\u0938 \u0936\u0940\u0930\u094d\u0937-\u092a\u0902\u0915\u094d\u0924\u093f \u0915\u0940 \u0938\u094d\u0925\u093e\u092f\u0940 \u0915\u095c\u0940", "Please activate JavaScript to enable the search\n functionality.": "\u0916\u094b\u091c \u0915\u093e\u0930\u094d\u092f \u0915\u0947 \u0932\u093f\u090f \u091c\u093e\u0935\u093e \u0938\u094d\u0915\u094d\u0930\u093f\u092a\u094d\u091f \u0915\u093e \u0939\u094b\u0928\u093e \u0906\u0935\u0936\u094d\u092f\u0915 \u0939\u0948. \u0915\u0943\u092a\u092f\u093e \u091c\u093e\u0935\u093e \u0938\u094d\u0915\u094d\u0930\u093f\u092a\u094d\u091f \u0915\u094b \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902.", "Preparing search...": "\u0916\u094b\u091c \u0915\u0940 \u0924\u0948\u092f\u093e\u0930\u0940", "Previous topic": "\u092a\u093f\u091b\u0932\u093e \u092a\u094d\u0930\u0915\u0930\u0923", "Quick search": "\u0924\u094d\u0935\u0930\u093f\u0924 \u0916\u094b\u091c", "Search": "\u0916\u094b\u091c", "Search Page": "\u0916\u094b\u091c \u092a\u0943\u0937\u094d\u0920", "Search Results": "\u0916\u094b\u091c \u092a\u0930\u0940\u0923\u093e\u092e ", "Search finished, found %s page(s) matching the search query.": "\u0916\u094b\u091c \u092a\u0942\u0930\u094d\u0923, \u0916\u094b\u091c \u0935\u093f\u0937\u092f \u0915\u0947 \u0905\u0928\u0941\u0915\u0942\u0932 %s \u092a\u0943\u0937\u094d\u0920 \u092e\u093f\u0932\u093e (\u092e\u093f\u0932\u0947).", "Search within %(docstitle)s": "%(docstitle)s \u092e\u0947\u0902 \u0916\u094b\u091c\u0947\u0902", "Searching": "\u0916\u094b\u091c \u091c\u093e\u0930\u0940", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u0938\u094d\u0930\u094b\u0924 \u0926\u093f\u0916\u093e\u090f\u0901", "Table of Contents": "\u0935\u093f\u0937\u092f-\u0938\u0942\u091a\u0940", "This Page": "\u092f\u0939 \u092a\u0943\u0937\u094d\u0920 ", "Welcome! This is": "\u0928\u092e\u0938\u094d\u0924\u0947! \u092f\u0939 \u0939\u0948", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u0906\u092a\u0915\u0947 \u0916\u094b\u091c \u092a\u0930\u093f\u0923\u093e\u092e\u094b\u0902 \u092e\u0947\u0902 \u0915\u094b\u0908 \u092a\u094d\u0930\u0932\u0947\u0916 \u0928\u0939\u0940\u0902 \u092e\u093f\u0932\u093e. \u0915\u0943\u092a\u092f\u093e \u0938\u0941\u0928\u093f\u0936\u094d\u091a\u093f\u0924 \u0915\u0930\u0947\u0902 \u0915\u093f \u0938\u092d\u0940 \u0936\u092c\u094d\u0926\u094b\u0902 \u0915\u0940 \u0935\u0930\u094d\u0924\u0928\u0940 \u0936\u0941\u0926\u094d\u0927 \u0939\u0948 \u0914\u0930 \u0906\u092a\u0928\u0947 \u092f\u0925\u0947\u0937\u094d\u091f \u0936\u094d\u0930\u0947\u0923\u093f\u092f\u093e\u0902 \u091a\u0941\u0928\u0940 \u0939\u0948\u0902.", "all functions, classes, terms": "\u0938\u092d\u0940 \u0915\u093e\u0930\u094d\u092f\u092f\u0941\u0915\u094d\u0924\u093f\u092f\u093e\u0902, \u0935\u0930\u094d\u0917, \u0936\u092c\u094d\u0926", "can be huge": "\u092c\u0943\u0939\u0926\u093e\u0915\u093e\u0930 \u0939\u094b \u0938\u0915\u0924\u093e \u0939\u0948", "last updated": "\u0905\u0902\u0924\u093f\u092e \u092a\u0930\u093f\u0935\u0930\u094d\u0927\u0928", "lists all sections and subsections": "\u0938\u092d\u0940 \u0905\u0928\u0941\u092d\u093e\u0917\u094b\u0902 \u090f\u0935\u0902 \u0909\u092a-\u0905\u0928\u0941\u092d\u093e\u0917\u094b\u0902 \u0915\u0940 \u0938\u0942\u091a\u0940", "next chapter": "\u0905\u0917\u0932\u093e \u0905\u0927\u094d\u092f\u093e\u092f", "previous chapter": "\u092a\u093f\u091b\u0932\u093e \u0905\u0927\u094d\u092f\u093e\u092f", "quick access to all modules": "\u0938\u092d\u0940 \u092a\u094d\u0930\u092d\u093e\u0917 \u0924\u0915 \u0924\u0941\u0930\u0902\u0924 \u092a\u0939\u0941\u0901\u091a", "search": "\u0916\u094b\u091c", "search this documentation": "\u0907\u0938 \u0906\u0932\u0947\u0916 \u092e\u0947\u0902 \u0916\u094b\u091c\u0947\u0902", "the documentation for": "\u0906\u0932\u0947\u0916 \u0935\u093f\u0937\u092f"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "hi", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">\u0938\u0930\u094d\u0935\u093e\u0927\u093f\u0915\u093e\u0930</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© \u0938\u0930\u094d\u0935\u093e\u0927\u093f\u0915\u093e\u0930 %(copyright)s.", + ", in ": ", \u092e\u0947\u0902 ", + "About these documents": "\u0907\u0928 \u0932\u0947\u0916\u092a\u0924\u094d\u0930\u094b\u0902 \u0915\u0947 \u092c\u093e\u0930\u0947 \u092e\u0947\u0902", + "Automatically generated list of changes in version %(version)s": "\u0938\u0902\u0938\u094d\u0915\u0930\u0923 %(version)s \u092e\u0947\u0902 \u0938\u094d\u0935\u0924\u0903 \u0930\u091a\u093f\u0924 \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928\u094b\u0902 \u0915\u0940 \u0938\u0942\u091a\u0940", + "C API changes": "\u0938\u0940 \u0910.\u092a\u0940.\u0906\u0908. \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928", + "Changes in Version %(version)s — %(docstitle)s": "\u092a\u0930\u093f\u0935\u0930\u094d\u0924\u093f\u0924 \u0938\u0902\u0938\u094d\u0915\u0930\u0923 %(version)s — %(docstitle)s", + "Collapse sidebar": "\u0915\u093f\u0928\u093e\u0930\u0947 \u0915\u093e \u0938\u094d\u0925\u093e\u0928 \u0918\u091f\u093e\u090f\u0902", + "Complete Table of Contents": "\u0935\u093f\u0938\u094d\u0924\u0943\u0924 \u0935\u093f\u0937\u092f-\u0938\u0942\u091a\u0940", + "Contents": "\u0935\u093f\u0937\u092f \u0938\u093e\u092e\u093f\u0917\u094d\u0930\u0940", + "Copyright": "\u0938\u0930\u094d\u0935\u093e\u0927\u093f\u0915\u093e\u0930", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u0938\u0947 \u0928\u093f\u0930\u094d\u092e\u093f\u0924.", + "Expand sidebar": "\u0915\u093f\u0928\u093e\u0930\u0947 \u0915\u093e \u0938\u094d\u0925\u093e\u0928 \u092c\u095d\u093e\u090f\u0902", + "Full index on one page": "\u090f\u0915 \u092a\u0943\u0937\u094d\u0920 \u092a\u0930 \u092a\u0942\u0930\u0940 \u0905\u0928\u0941\u0915\u094d\u0930\u092e\u0923\u093f\u0915\u093e", + "General Index": "\u0938\u093e\u092e\u093e\u0928\u094d\u092f \u0905\u0928\u0941\u0915\u094d\u0930\u092e\u093e\u0923\u093f\u0915\u093e", + "Global Module Index": "\u0938\u093e\u0930\u094d\u0935\u092d\u094c\u092e\u093f\u0915 \u092a\u094d\u0930\u092d\u093e\u0917 \u0938\u0942\u091a\u0940", + "Go": "\u091a\u0932\u093f\u090f", + "Hide Search Matches": "\u0916\u094b\u091c\u0947 \u0917\u090f \u091c\u094b\u095c\u0947 \u091b\u093f\u092a\u093e\u090f\u0902", + "Index": "\u0905\u0928\u0941\u0915\u094d\u0930\u092e\u0923\u093f\u0915\u093e", + "Index – %(key)s": "\u0905\u0928\u0941\u0915\u094d\u0930\u092e\u0923\u093f\u0915\u093e – %(key)s", + "Index pages by letter": "\u0905\u0915\u094d\u0937\u0930 \u0926\u094d\u0935\u093e\u0930\u093e \u0905\u0928\u0941\u0915\u094d\u0930\u092e\u093f\u0924 \u092a\u0943\u0937\u094d\u0920", + "Indices and tables:": "\u0938\u0942\u091a\u093f\u092f\u093e\u0901 \u0914\u0930 \u0938\u093e\u0930\u0923\u093f\u092f\u093e\u0901:", + "Last updated on %(last_updated)s.": "\u0905\u0902\u0924\u093f\u092e \u092c\u093e\u0930 \u0938\u092e\u094d\u092a\u093e\u0926\u093f\u0924 %(last_updated)s.", + "Library changes": "\u092a\u0941\u0938\u094d\u0924\u0915\u093e\u0932\u092f \u092e\u0947\u0902 \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928", + "Navigation": "\u0938\u0902\u091a\u093e\u0932\u0928", + "Next topic": "\u0905\u0917\u0932\u093e \u092a\u094d\u0930\u0915\u0930\u0923", + "Other changes": "\u0905\u0928\u094d\u092f \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928", + "Overview": "\u0938\u093f\u0902\u0939\u093e\u0935\u0932\u094b\u0915\u0928", + "Permalink to this definition": "\u0907\u0938 \u092a\u0930\u093f\u092d\u093e\u0937\u093e \u0915\u0940 \u0938\u094d\u0925\u093e\u092f\u0940 \u0915\u095c\u0940", + "Permalink to this headline": "\u0907\u0938 \u0936\u0940\u0930\u094d\u0937-\u092a\u0902\u0915\u094d\u0924\u093f \u0915\u0940 \u0938\u094d\u0925\u093e\u092f\u0940 \u0915\u095c\u0940", + "Please activate JavaScript to enable the search\n functionality.": "\u0916\u094b\u091c \u0915\u093e\u0930\u094d\u092f \u0915\u0947 \u0932\u093f\u090f \u091c\u093e\u0935\u093e \u0938\u094d\u0915\u094d\u0930\u093f\u092a\u094d\u091f \u0915\u093e \u0939\u094b\u0928\u093e \u0906\u0935\u0936\u094d\u092f\u0915 \u0939\u0948. \u0915\u0943\u092a\u092f\u093e \u091c\u093e\u0935\u093e \u0938\u094d\u0915\u094d\u0930\u093f\u092a\u094d\u091f \u0915\u094b \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902.", + "Preparing search...": "\u0916\u094b\u091c \u0915\u0940 \u0924\u0948\u092f\u093e\u0930\u0940", + "Previous topic": "\u092a\u093f\u091b\u0932\u093e \u092a\u094d\u0930\u0915\u0930\u0923", + "Quick search": "\u0924\u094d\u0935\u0930\u093f\u0924 \u0916\u094b\u091c", + "Search": "\u0916\u094b\u091c", + "Search Page": "\u0916\u094b\u091c \u092a\u0943\u0937\u094d\u0920", + "Search Results": "\u0916\u094b\u091c \u092a\u0930\u0940\u0923\u093e\u092e ", + "Search finished, found %s page(s) matching the search query.": "\u0916\u094b\u091c \u092a\u0942\u0930\u094d\u0923, \u0916\u094b\u091c \u0935\u093f\u0937\u092f \u0915\u0947 \u0905\u0928\u0941\u0915\u0942\u0932 %s \u092a\u0943\u0937\u094d\u0920 \u092e\u093f\u0932\u093e (\u092e\u093f\u0932\u0947).", + "Search within %(docstitle)s": "%(docstitle)s \u092e\u0947\u0902 \u0916\u094b\u091c\u0947\u0902", + "Searching": "\u0916\u094b\u091c \u091c\u093e\u0930\u0940", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u0938\u094d\u0930\u094b\u0924 \u0926\u093f\u0916\u093e\u090f\u0901", + "Table of Contents": "\u0935\u093f\u0937\u092f-\u0938\u0942\u091a\u0940", + "This Page": "\u092f\u0939 \u092a\u0943\u0937\u094d\u0920 ", + "Welcome! This is": "\u0928\u092e\u0938\u094d\u0924\u0947! \u092f\u0939 \u0939\u0948", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u0906\u092a\u0915\u0947 \u0916\u094b\u091c \u092a\u0930\u093f\u0923\u093e\u092e\u094b\u0902 \u092e\u0947\u0902 \u0915\u094b\u0908 \u092a\u094d\u0930\u0932\u0947\u0916 \u0928\u0939\u0940\u0902 \u092e\u093f\u0932\u093e. \u0915\u0943\u092a\u092f\u093e \u0938\u0941\u0928\u093f\u0936\u094d\u091a\u093f\u0924 \u0915\u0930\u0947\u0902 \u0915\u093f \u0938\u092d\u0940 \u0936\u092c\u094d\u0926\u094b\u0902 \u0915\u0940 \u0935\u0930\u094d\u0924\u0928\u0940 \u0936\u0941\u0926\u094d\u0927 \u0939\u0948 \u0914\u0930 \u0906\u092a\u0928\u0947 \u092f\u0925\u0947\u0937\u094d\u091f \u0936\u094d\u0930\u0947\u0923\u093f\u092f\u093e\u0902 \u091a\u0941\u0928\u0940 \u0939\u0948\u0902.", + "all functions, classes, terms": "\u0938\u092d\u0940 \u0915\u093e\u0930\u094d\u092f\u092f\u0941\u0915\u094d\u0924\u093f\u092f\u093e\u0902, \u0935\u0930\u094d\u0917, \u0936\u092c\u094d\u0926", + "can be huge": "\u092c\u0943\u0939\u0926\u093e\u0915\u093e\u0930 \u0939\u094b \u0938\u0915\u0924\u093e \u0939\u0948", + "last updated": "\u0905\u0902\u0924\u093f\u092e \u092a\u0930\u093f\u0935\u0930\u094d\u0927\u0928", + "lists all sections and subsections": "\u0938\u092d\u0940 \u0905\u0928\u0941\u092d\u093e\u0917\u094b\u0902 \u090f\u0935\u0902 \u0909\u092a-\u0905\u0928\u0941\u092d\u093e\u0917\u094b\u0902 \u0915\u0940 \u0938\u0942\u091a\u0940", + "next chapter": "\u0905\u0917\u0932\u093e \u0905\u0927\u094d\u092f\u093e\u092f", + "previous chapter": "\u092a\u093f\u091b\u0932\u093e \u0905\u0927\u094d\u092f\u093e\u092f", + "quick access to all modules": "\u0938\u092d\u0940 \u092a\u094d\u0930\u092d\u093e\u0917 \u0924\u0915 \u0924\u0941\u0930\u0902\u0924 \u092a\u0939\u0941\u0901\u091a", + "search": "\u0916\u094b\u091c", + "search this documentation": "\u0907\u0938 \u0906\u0932\u0947\u0916 \u092e\u0947\u0902 \u0916\u094b\u091c\u0947\u0902", + "the documentation for": "\u0906\u0932\u0947\u0916 \u0935\u093f\u0937\u092f" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/hi/LC_MESSAGES/sphinx.po b/sphinx/locale/hi/LC_MESSAGES/sphinx.po index 7fd40316b..5effb078c 100644 --- a/sphinx/locale/hi/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hi/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Ajay Singh <ajaysajay@gmail.com>, 2019 # Purnank H. Ghumalia <me@purnank.in>, 2015-2016 diff --git a/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.js b/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.js index bb8d33611..8319d94fd 100644 --- a/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "hi_IN", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "hi_IN", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po b/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po index 78f66e29e..b1047a51f 100644 --- a/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/hr/LC_MESSAGES/sphinx.js b/sphinx/locale/hr/LC_MESSAGES/sphinx.js index 05aaa3ce1..b283b344c 100644 --- a/sphinx/locale/hr/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/hr/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "hr", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Sva prava zadr\u017eana</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Sva prava zadr\u017eana %(copyright)s.", ", in ": ", u ", "About these documents": "O ovim dokumentima", "Automatically generated list of changes in version %(version)s": "Automatski generirani popis promjena u verziji %(version)s", "C API changes": "C API promjene", "Changes in Version %(version)s — %(docstitle)s": "Promjene u verziji %(version)s — %(docstitle)s", "Collapse sidebar": "Sakrij pomo\u0107nu traku", "Complete Table of Contents": "Detaljni sadr\u017eaj", "Contents": "Sadr\u017eaj", "Copyright": "Sva prava zadr\u017eana", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Izra\u0111eno sa <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Poka\u017ei pomo\u0107nu traku", "Full index on one page": "Potpun indeks na jednoj stranici", "General Index": "Opceniti abecedni indeks", "Global Module Index": "Op\u0107eniti popis modula", "Go": "Tra\u017ei", "Hide Search Matches": "Sakrij rezultate pretrage", "Index": "Abecedni popis", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "Indeksiraj stranice po slovu", "Indices and tables:": "Kazala i tablice:", "Last updated on %(last_updated)s.": "Zadnji put a\u017eurirano %(last_updated)s.", "Library changes": "Promjene lib-ova", "Navigation": "Navigacija", "Next topic": "Sljede\u0107a tema", "Other changes": "Ostale promjene", "Overview": "Pregled", "Permalink to this definition": "Link na tu definiciju", "Permalink to this headline": "Link na taj naslov", "Please activate JavaScript to enable the search\n functionality.": "Molimo omogu\u0107ite JavaScript\n za djelovanje tra\u017eilice.", "Preparing search...": "Priprema pretrage...", "Previous topic": "Prija\u0161nja tema", "Quick search": "Brzo pretra\u017eivanje", "Search": "Tra\u017ei", "Search Page": "Tra\u017eilica", "Search Results": "Rezultati pretrage", "Search finished, found %s page(s) matching the search query.": "Pretraga zavr\u0161ena, prona\u0111eno %s stranica.", "Search within %(docstitle)s": "Tra\u017ei izme\u0111u %(docstitle)s", "Searching": "Pretra\u017eivanje", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Prika\u017ei izvorni kod", "Table of Contents": "", "This Page": "Trenutna stranica", "Welcome! This is": "Dobro do\u0161li! Ovo je", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Zadanim uvjetima nije prona\u0111en dokument. Molim provjerite to\u010dnost upisanih rije\u010di i odabir ozna\u010denih kategija.", "all functions, classes, terms": "sve funkcije, razredi, izrazi", "can be huge": "mo\u017ee biti ogromno", "last updated": "posljednja promjena", "lists all sections and subsections": "prika\u017ei sve sekcije i podsekcije", "next chapter": "sljede\u0107e poglavlje", "previous chapter": "Prija\u0161nje poglavlje", "quick access to all modules": "brz dostup do svih modula", "search": "tra\u017ei", "search this documentation": "tra\u017ei po dokumentaciji", "the documentation for": "dokumentacija za"}, "plural_expr": "n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "hr", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Sva prava zadr\u017eana</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Sva prava zadr\u017eana %(copyright)s.", + ", in ": ", u ", + "About these documents": "O ovim dokumentima", + "Automatically generated list of changes in version %(version)s": "Automatski generirani popis promjena u verziji %(version)s", + "C API changes": "C API promjene", + "Changes in Version %(version)s — %(docstitle)s": "Promjene u verziji %(version)s — %(docstitle)s", + "Collapse sidebar": "Sakrij pomo\u0107nu traku", + "Complete Table of Contents": "Detaljni sadr\u017eaj", + "Contents": "Sadr\u017eaj", + "Copyright": "Sva prava zadr\u017eana", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Izra\u0111eno sa <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Poka\u017ei pomo\u0107nu traku", + "Full index on one page": "Potpun indeks na jednoj stranici", + "General Index": "Opceniti abecedni indeks", + "Global Module Index": "Op\u0107eniti popis modula", + "Go": "Tra\u017ei", + "Hide Search Matches": "Sakrij rezultate pretrage", + "Index": "Abecedni popis", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "Indeksiraj stranice po slovu", + "Indices and tables:": "Kazala i tablice:", + "Last updated on %(last_updated)s.": "Zadnji put a\u017eurirano %(last_updated)s.", + "Library changes": "Promjene lib-ova", + "Navigation": "Navigacija", + "Next topic": "Sljede\u0107a tema", + "Other changes": "Ostale promjene", + "Overview": "Pregled", + "Permalink to this definition": "Link na tu definiciju", + "Permalink to this headline": "Link na taj naslov", + "Please activate JavaScript to enable the search\n functionality.": "Molimo omogu\u0107ite JavaScript\n za djelovanje tra\u017eilice.", + "Preparing search...": "Priprema pretrage...", + "Previous topic": "Prija\u0161nja tema", + "Quick search": "Brzo pretra\u017eivanje", + "Search": "Tra\u017ei", + "Search Page": "Tra\u017eilica", + "Search Results": "Rezultati pretrage", + "Search finished, found %s page(s) matching the search query.": "Pretraga zavr\u0161ena, prona\u0111eno %s stranica.", + "Search within %(docstitle)s": "Tra\u017ei izme\u0111u %(docstitle)s", + "Searching": "Pretra\u017eivanje", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Prika\u017ei izvorni kod", + "Table of Contents": "", + "This Page": "Trenutna stranica", + "Welcome! This is": "Dobro do\u0161li! Ovo je", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Zadanim uvjetima nije prona\u0111en dokument. Molim provjerite to\u010dnost upisanih rije\u010di i odabir ozna\u010denih kategija.", + "all functions, classes, terms": "sve funkcije, razredi, izrazi", + "can be huge": "mo\u017ee biti ogromno", + "last updated": "posljednja promjena", + "lists all sections and subsections": "prika\u017ei sve sekcije i podsekcije", + "next chapter": "sljede\u0107e poglavlje", + "previous chapter": "Prija\u0161nje poglavlje", + "quick access to all modules": "brz dostup do svih modula", + "search": "tra\u017ei", + "search this documentation": "tra\u017ei po dokumentaciji", + "the documentation for": "dokumentacija za" + }, + "plural_expr": "n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2" +});
\ No newline at end of file diff --git a/sphinx/locale/hr/LC_MESSAGES/sphinx.po b/sphinx/locale/hr/LC_MESSAGES/sphinx.po index c1f1d4be0..20e336487 100644 --- a/sphinx/locale/hr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hr/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Mario Šarić, 2015-2020 msgid "" diff --git a/sphinx/locale/hu/LC_MESSAGES/sphinx.js b/sphinx/locale/hu/LC_MESSAGES/sphinx.js index 31b266b34..663ef6134 100644 --- a/sphinx/locale/hu/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/hu/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "hu", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": ", ", "About these documents": "N\u00e9vjegy ezekr\u0151l a dokumentumokr\u00f3l", "Automatically generated list of changes in version %(version)s": "Automatikusan gener\u00e1lt v\u00e1ltoz\u00e1slista a(z) %(version)s v\u00e1ltozathoz", "C API changes": "C API v\u00e1ltoz\u00e1sok", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Oldals\u00e1v \u00f6sszez\u00e1r\u00e1sa", "Complete Table of Contents": "Teljes tartalomjegyz\u00e9k", "Contents": "Tartalom", "Copyright": "Minden jog fenntartva", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s haszn\u00e1lat\u00e1val k\u00e9sz\u00fclt.", "Expand sidebar": "Oldals\u00e1v kinyit\u00e1sa", "Full index on one page": "Teljes t\u00e1rgymutat\u00f3 egy oldalon", "General Index": "\u00c1ltal\u00e1nos t\u00e1rgymutat\u00f3", "Global Module Index": "Teljes modul t\u00e1rgymutat\u00f3", "Go": "Ok", "Hide Search Matches": "Keres\u00e9si Tal\u00e1latok Elrejt\u00e9se", "Index": "T\u00e1rgymutat\u00f3", "Index – %(key)s": "T\u00e1rgymutat\u00f3 – %(key)s", "Index pages by letter": "Oldalak ABC sorrendben", "Indices and tables:": "T\u00e1rgymutat\u00f3 \u00e9s t\u00e1bl\u00e1zatok", "Last updated on %(last_updated)s.": "Utols\u00f3 friss\u00edt\u00e9s %(last_updated)s.", "Library changes": "K\u00f6nyvt\u00e1r v\u00e1ltoz\u00e1sok", "Navigation": "Navig\u00e1ci\u00f3", "Next topic": "K\u00f6vetkez\u0151 t\u00e9mak\u00f6r", "Other changes": "Egy\u00e9b v\u00e1ltoz\u00e1sok", "Overview": "\u00c1ttekint\u00e9s", "Permalink to this definition": "Hivatkoz\u00e1s erre a defin\u00edci\u00f3ra", "Permalink to this headline": "Hivatkoz\u00e1s erre a fejezetc\u00edmre", "Please activate JavaScript to enable the search\n functionality.": "K\u00e9rem enged\u00e9lyezze a JavaScriptet a keres\u0151 funkci\u00f3\n haszn\u00e1lat\u00e1hoz.", "Preparing search...": "Felk\u00e9sz\u00fcl\u00e9s a keres\u00e9sre...", "Previous topic": "El\u0151z\u0151 t\u00e9mak\u00f6r", "Quick search": "Gyorskeres\u00e9s", "Search": "Keres\u00e9s", "Search Page": "Keres\u00e9s", "Search Results": "Keres\u00e9si Eredm\u00e9nyek", "Search finished, found %s page(s) matching the search query.": "A keres\u00e9s befejez\u0151d\u00f6tt, %s oldal egyezik a keres\u00e9si fel\u00e9teleknek.", "Search within %(docstitle)s": "Keres\u00e9s k\u00f6zt\u00fck: %(docstitle)s", "Searching": "Keres\u00e9s folyamatban", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Forr\u00e1s megtekint\u00e9se", "Table of Contents": "", "This Page": "Ez az Oldal", "Welcome! This is": "\u00dcdv\u00f6z\u00f6lj\u00fck! Ez a", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "A keres\u00e9se nem hozott eredm\u00e9nyt. Ellen\u0151rizze, a megadott kulcsszavakat \u00e9s azt, hogy megfelel\u0151 sz\u00e1m\u00fa kateg\u00f3ria van-e kiv\u00e1lasztva.", "all functions, classes, terms": "\u00f6sszes funkci\u00f3, oszt\u00e1ly \u00e9s kifejez\u00e9s", "can be huge": "nagy lehet", "last updated": "utolj\u00e1ra friss\u00edtve", "lists all sections and subsections": "kilist\u00e1zza az \u00f6sszes fejezetet \u00e9s alfejezetet", "next chapter": "k\u00f6vetkez\u0151 fejezet", "previous chapter": "el\u0151z\u0151 fejezet", "quick access to all modules": "gyors hozz\u00e1f\u00e9r\u00e9s az \u00f6sszes modulhoz", "search": "keres\u00e9s", "search this documentation": "keres\u00e9s ebben a dokument\u00e1ci\u00f3ban", "the documentation for": "dokument\u00e1ci\u00f3"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "hu", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": ", ", + "About these documents": "N\u00e9vjegy ezekr\u0151l a dokumentumokr\u00f3l", + "Automatically generated list of changes in version %(version)s": "Automatikusan gener\u00e1lt v\u00e1ltoz\u00e1slista a(z) %(version)s v\u00e1ltozathoz", + "C API changes": "C API v\u00e1ltoz\u00e1sok", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Oldals\u00e1v \u00f6sszez\u00e1r\u00e1sa", + "Complete Table of Contents": "Teljes tartalomjegyz\u00e9k", + "Contents": "Tartalom", + "Copyright": "Minden jog fenntartva", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s haszn\u00e1lat\u00e1val k\u00e9sz\u00fclt.", + "Expand sidebar": "Oldals\u00e1v kinyit\u00e1sa", + "Full index on one page": "Teljes t\u00e1rgymutat\u00f3 egy oldalon", + "General Index": "\u00c1ltal\u00e1nos t\u00e1rgymutat\u00f3", + "Global Module Index": "Teljes modul t\u00e1rgymutat\u00f3", + "Go": "Ok", + "Hide Search Matches": "Keres\u00e9si Tal\u00e1latok Elrejt\u00e9se", + "Index": "T\u00e1rgymutat\u00f3", + "Index – %(key)s": "T\u00e1rgymutat\u00f3 – %(key)s", + "Index pages by letter": "Oldalak ABC sorrendben", + "Indices and tables:": "T\u00e1rgymutat\u00f3 \u00e9s t\u00e1bl\u00e1zatok", + "Last updated on %(last_updated)s.": "Utols\u00f3 friss\u00edt\u00e9s %(last_updated)s.", + "Library changes": "K\u00f6nyvt\u00e1r v\u00e1ltoz\u00e1sok", + "Navigation": "Navig\u00e1ci\u00f3", + "Next topic": "K\u00f6vetkez\u0151 t\u00e9mak\u00f6r", + "Other changes": "Egy\u00e9b v\u00e1ltoz\u00e1sok", + "Overview": "\u00c1ttekint\u00e9s", + "Permalink to this definition": "Hivatkoz\u00e1s erre a defin\u00edci\u00f3ra", + "Permalink to this headline": "Hivatkoz\u00e1s erre a fejezetc\u00edmre", + "Please activate JavaScript to enable the search\n functionality.": "K\u00e9rem enged\u00e9lyezze a JavaScriptet a keres\u0151 funkci\u00f3\n haszn\u00e1lat\u00e1hoz.", + "Preparing search...": "Felk\u00e9sz\u00fcl\u00e9s a keres\u00e9sre...", + "Previous topic": "El\u0151z\u0151 t\u00e9mak\u00f6r", + "Quick search": "Gyorskeres\u00e9s", + "Search": "Keres\u00e9s", + "Search Page": "Keres\u00e9s", + "Search Results": "Keres\u00e9si Eredm\u00e9nyek", + "Search finished, found %s page(s) matching the search query.": "A keres\u00e9s befejez\u0151d\u00f6tt, %s oldal egyezik a keres\u00e9si fel\u00e9teleknek.", + "Search within %(docstitle)s": "Keres\u00e9s k\u00f6zt\u00fck: %(docstitle)s", + "Searching": "Keres\u00e9s folyamatban", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Forr\u00e1s megtekint\u00e9se", + "Table of Contents": "", + "This Page": "Ez az Oldal", + "Welcome! This is": "\u00dcdv\u00f6z\u00f6lj\u00fck! Ez a", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "A keres\u00e9se nem hozott eredm\u00e9nyt. Ellen\u0151rizze, a megadott kulcsszavakat \u00e9s azt, hogy megfelel\u0151 sz\u00e1m\u00fa kateg\u00f3ria van-e kiv\u00e1lasztva.", + "all functions, classes, terms": "\u00f6sszes funkci\u00f3, oszt\u00e1ly \u00e9s kifejez\u00e9s", + "can be huge": "nagy lehet", + "last updated": "utolj\u00e1ra friss\u00edtve", + "lists all sections and subsections": "kilist\u00e1zza az \u00f6sszes fejezetet \u00e9s alfejezetet", + "next chapter": "k\u00f6vetkez\u0151 fejezet", + "previous chapter": "el\u0151z\u0151 fejezet", + "quick access to all modules": "gyors hozz\u00e1f\u00e9r\u00e9s az \u00f6sszes modulhoz", + "search": "keres\u00e9s", + "search this documentation": "keres\u00e9s ebben a dokument\u00e1ci\u00f3ban", + "the documentation for": "dokument\u00e1ci\u00f3" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/hu/LC_MESSAGES/sphinx.po b/sphinx/locale/hu/LC_MESSAGES/sphinx.po index fe58d1895..ecf147f1f 100644 --- a/sphinx/locale/hu/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hu/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2011 # Molnár Dénes <denes.molnar2@stud.uni-corvinus.hu>, 2017 diff --git a/sphinx/locale/id/LC_MESSAGES/sphinx.js b/sphinx/locale/id/LC_MESSAGES/sphinx.js index ccb7a8b3d..8ed465668 100644 --- a/sphinx/locale/id/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/id/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "id", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Hak cipta</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Hak cipta %(copyright)s.", ", in ": ", di", "About these documents": "Tentang dokumen ini", "Automatically generated list of changes in version %(version)s": "Daftar perubahan dibuat otomatis untuk versi %(version)s", "C API changes": "Perubahan API C", "Changes in Version %(version)s — %(docstitle)s": "Perubahan pada Versi %(version)s — %(docstitle)s", "Collapse sidebar": "Tutup sidebar", "Complete Table of Contents": "Daftar Isi Lengkap", "Contents": "Konten", "Copyright": "Hak Cipta", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Dibuat menggunakan <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Buka sidebar", "Full index on one page": "Index penuh dalam satu halaman", "General Index": "Indeks Umum", "Global Module Index": "Index Modul Global", "Go": "Go", "Hide Search Matches": "Sembunyikan Hasil Pencarian", "Index": "Indeks", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "Index halaman berdasarkan huruf", "Indices and tables:": "Indeks dan tabel:", "Last updated on %(last_updated)s.": "Terakhir diperbarui pada %(last_updated)s.", "Library changes": "Perubahan library", "Navigation": "Navigasi", "Next topic": "Topik berikutnya", "Other changes": "Perubahan lain", "Overview": "Tinjauan", "Permalink to this definition": "Link permanen untuk definisi ini", "Permalink to this headline": "Link permanen untuk headline ini", "Please activate JavaScript to enable the search\n functionality.": "Tolong aktifkan JavaScript untuk melakukan pencarian.\n ", "Preparing search...": "Penyiapkan pencarian...", "Previous topic": "Topik sebelumnya", "Quick search": "Pencarian cepat", "Search": "Pencarian", "Search Page": "Pencarian Halaman", "Search Results": "Hasil Pencarian", "Search finished, found %s page(s) matching the search query.": "Pencarian selesai, menemukan %s halaman yang cocok dengan kueri pencarian.", "Search within %(docstitle)s": "Pencarian dalam %(docstitle)s", "Searching": "Pencarian", "Searching for multiple words only shows matches that contain\n all words.": "Mencari beberapa kata hanya menunjukkan kecocokan yang mengandung\n \u00a0\u00a0 semua kata.", "Show Source": "Lihat Sumber", "Table of Contents": "Daftar Isi", "This Page": "Halaman Ini", "Welcome! This is": "Selamat Datang! Ini adalah", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Tidak ada dokumen yang cocok dengan pencarian anda. Pastikan semua kata ditulis dengan benar dan sudah memilih cukup kategori.", "all functions, classes, terms": "semua fungsi, class, term", "can be huge": "dapat menjadi besar", "last updated": "terakhir diperbarui", "lists all sections and subsections": "daftar semua seksi dan subseksi", "next chapter": "bab berikutnya", "previous chapter": "bab sebelum", "quick access to all modules": "akses cepat semua modul", "search": "pencarian", "search this documentation": "pencarian pada dokumentasi ini", "the documentation for": "dokumentasi untuk"}, "plural_expr": "0"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "id", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Hak cipta</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Hak cipta %(copyright)s.", + ", in ": ", di", + "About these documents": "Tentang dokumen ini", + "Automatically generated list of changes in version %(version)s": "Daftar perubahan dibuat otomatis untuk versi %(version)s", + "C API changes": "Perubahan API C", + "Changes in Version %(version)s — %(docstitle)s": "Perubahan pada Versi %(version)s — %(docstitle)s", + "Collapse sidebar": "Tutup sidebar", + "Complete Table of Contents": "Daftar Isi Lengkap", + "Contents": "Konten", + "Copyright": "Hak Cipta", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Dibuat menggunakan <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Buka sidebar", + "Full index on one page": "Index penuh dalam satu halaman", + "General Index": "Indeks Umum", + "Global Module Index": "Index Modul Global", + "Go": "Go", + "Hide Search Matches": "Sembunyikan Hasil Pencarian", + "Index": "Indeks", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "Index halaman berdasarkan huruf", + "Indices and tables:": "Indeks dan tabel:", + "Last updated on %(last_updated)s.": "Terakhir diperbarui pada %(last_updated)s.", + "Library changes": "Perubahan library", + "Navigation": "Navigasi", + "Next topic": "Topik berikutnya", + "Other changes": "Perubahan lain", + "Overview": "Tinjauan", + "Permalink to this definition": "Link permanen untuk definisi ini", + "Permalink to this headline": "Link permanen untuk headline ini", + "Please activate JavaScript to enable the search\n functionality.": "Tolong aktifkan JavaScript untuk melakukan pencarian.\n ", + "Preparing search...": "Penyiapkan pencarian...", + "Previous topic": "Topik sebelumnya", + "Quick search": "Pencarian cepat", + "Search": "Pencarian", + "Search Page": "Pencarian Halaman", + "Search Results": "Hasil Pencarian", + "Search finished, found %s page(s) matching the search query.": "Pencarian selesai, menemukan %s halaman yang cocok dengan kueri pencarian.", + "Search within %(docstitle)s": "Pencarian dalam %(docstitle)s", + "Searching": "Pencarian", + "Searching for multiple words only shows matches that contain\n all words.": "Mencari beberapa kata hanya menunjukkan kecocokan yang mengandung\n \u00a0\u00a0 semua kata.", + "Show Source": "Lihat Sumber", + "Table of Contents": "Daftar Isi", + "This Page": "Halaman Ini", + "Welcome! This is": "Selamat Datang! Ini adalah", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Tidak ada dokumen yang cocok dengan pencarian anda. Pastikan semua kata ditulis dengan benar dan sudah memilih cukup kategori.", + "all functions, classes, terms": "semua fungsi, class, term", + "can be huge": "dapat menjadi besar", + "last updated": "terakhir diperbarui", + "lists all sections and subsections": "daftar semua seksi dan subseksi", + "next chapter": "bab berikutnya", + "previous chapter": "bab sebelum", + "quick access to all modules": "akses cepat semua modul", + "search": "pencarian", + "search this documentation": "pencarian pada dokumentasi ini", + "the documentation for": "dokumentasi untuk" + }, + "plural_expr": "0" +});
\ No newline at end of file diff --git a/sphinx/locale/id/LC_MESSAGES/sphinx.po b/sphinx/locale/id/LC_MESSAGES/sphinx.po index d11a59d35..d1ff01f34 100644 --- a/sphinx/locale/id/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/id/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Arif Budiman <arifpedia@gmail.com>, 2016-2017 # FIRST AUTHOR <EMAIL@ADDRESS>, 2009 diff --git a/sphinx/locale/it/LC_MESSAGES/sphinx.js b/sphinx/locale/it/LC_MESSAGES/sphinx.js index 3a75265de..1b763f01f 100644 --- a/sphinx/locale/it/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/it/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "it", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", in ", "About these documents": "A proposito di questi documenti", "Automatically generated list of changes in version %(version)s": "Lista delle modifiche generata automaticamente nella versione %(version)s", "C API changes": "Modifiche nelle API C", "Changes in Version %(version)s — %(docstitle)s": "Cambiamenti nella Versione %(version)s — %(docstitle)s", "Collapse sidebar": "Comprimi la barra laterale", "Complete Table of Contents": "Tabella dei contenuti completa", "Contents": "Contenuti", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Creato con <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Espandi la barra laterale", "Full index on one page": "Indice completo in una pagina", "General Index": "Indice generale", "Global Module Index": "Indice dei moduli", "Go": "Vai", "Hide Search Matches": "Nascondi i risultati della ricerca", "Index": "Indice", "Index – %(key)s": "Indice – %(key)s", "Index pages by letter": "Indice delle pagine per lettera", "Indices and tables:": "Indici e tabelle:", "Last updated on %(last_updated)s.": "Ultimo aggiornamento %(last_updated)s.", "Library changes": "Modifiche nella libreria", "Navigation": "Navigazione", "Next topic": "Argomento successivo", "Other changes": "Altre modifiche", "Overview": "Sintesi", "Permalink to this definition": "Link a questa definizione", "Permalink to this headline": "Link a questa intestazione", "Please activate JavaScript to enable the search\n functionality.": "Attiva JavaScript per abilitare la funzione\u23ce\ndi ricerca.", "Preparing search...": "Preparo la ricerca...", "Previous topic": "Argomento precedente", "Quick search": "Ricerca veloce", "Search": "Cerca", "Search Page": "Cerca", "Search Results": "Risultati della ricerca", "Search finished, found %s page(s) matching the search query.": "Ricerca completata, trovata/e %s pagina/e corrispondenti.", "Search within %(docstitle)s": "Cerca in %(docstitle)s", "Searching": "Cerca", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Mostra sorgente", "Table of Contents": "", "This Page": "Questa pagina", "Welcome! This is": "Benvenuto! Questa \u00e8", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "La tua ricerca non corrisponde a nessun documento. Verifica che tutte le parole siano scritte correttamente e di aver scelto un numero sufficiente di categorie.", "all functions, classes, terms": "tutte le funzioni, classi e moduli", "can be huge": "pu\u00f2 essere enorme", "last updated": "ultimo aggiornamento", "lists all sections and subsections": "elenca l'insieme delle sezioni e sottosezioni", "next chapter": "capitolo successivo", "previous chapter": "capitolo precedente", "quick access to all modules": "accesso veloce ai moduli", "search": "cerca", "search this documentation": "cerca in questa documentazione", "the documentation for": "la documentazione per"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "it", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", in ", + "About these documents": "A proposito di questi documenti", + "Automatically generated list of changes in version %(version)s": "Lista delle modifiche generata automaticamente nella versione %(version)s", + "C API changes": "Modifiche nelle API C", + "Changes in Version %(version)s — %(docstitle)s": "Cambiamenti nella Versione %(version)s — %(docstitle)s", + "Collapse sidebar": "Comprimi la barra laterale", + "Complete Table of Contents": "Tabella dei contenuti completa", + "Contents": "Contenuti", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Creato con <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Espandi la barra laterale", + "Full index on one page": "Indice completo in una pagina", + "General Index": "Indice generale", + "Global Module Index": "Indice dei moduli", + "Go": "Vai", + "Hide Search Matches": "Nascondi i risultati della ricerca", + "Index": "Indice", + "Index – %(key)s": "Indice – %(key)s", + "Index pages by letter": "Indice delle pagine per lettera", + "Indices and tables:": "Indici e tabelle:", + "Last updated on %(last_updated)s.": "Ultimo aggiornamento %(last_updated)s.", + "Library changes": "Modifiche nella libreria", + "Navigation": "Navigazione", + "Next topic": "Argomento successivo", + "Other changes": "Altre modifiche", + "Overview": "Sintesi", + "Permalink to this definition": "Link a questa definizione", + "Permalink to this headline": "Link a questa intestazione", + "Please activate JavaScript to enable the search\n functionality.": "Attiva JavaScript per abilitare la funzione\u23ce\ndi ricerca.", + "Preparing search...": "Preparo la ricerca...", + "Previous topic": "Argomento precedente", + "Quick search": "Ricerca veloce", + "Search": "Cerca", + "Search Page": "Cerca", + "Search Results": "Risultati della ricerca", + "Search finished, found %s page(s) matching the search query.": "Ricerca completata, trovata/e %s pagina/e corrispondenti.", + "Search within %(docstitle)s": "Cerca in %(docstitle)s", + "Searching": "Cerca", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Mostra sorgente", + "Table of Contents": "", + "This Page": "Questa pagina", + "Welcome! This is": "Benvenuto! Questa \u00e8", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "La tua ricerca non corrisponde a nessun documento. Verifica che tutte le parole siano scritte correttamente e di aver scelto un numero sufficiente di categorie.", + "all functions, classes, terms": "tutte le funzioni, classi e moduli", + "can be huge": "pu\u00f2 essere enorme", + "last updated": "ultimo aggiornamento", + "lists all sections and subsections": "elenca l'insieme delle sezioni e sottosezioni", + "next chapter": "capitolo successivo", + "previous chapter": "capitolo precedente", + "quick access to all modules": "accesso veloce ai moduli", + "search": "cerca", + "search this documentation": "cerca in questa documentazione", + "the documentation for": "la documentazione per" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/it/LC_MESSAGES/sphinx.po b/sphinx/locale/it/LC_MESSAGES/sphinx.po index 9c871d0d2..c0aeb2e06 100644 --- a/sphinx/locale/it/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/it/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Denis Cappellin <denis@cappell.in>, 2018 # Paolo Cavallini <cavallini@faunalia.it>, 2013-2017 diff --git a/sphinx/locale/ja/LC_MESSAGES/sphinx.js b/sphinx/locale/ja/LC_MESSAGES/sphinx.js index 0b9dc3f95..b2c02c260 100644 --- a/sphinx/locale/ja/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ja/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ja", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", in ", "About these documents": "\u3053\u306e\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306b\u3064\u3044\u3066", "Automatically generated list of changes in version %(version)s": "\u30d0\u30fc\u30b8\u30e7\u30f3 %(version)s \u306e\u5909\u66f4\u70b9\uff08\u3053\u306e\u30ea\u30b9\u30c8\u306f\u81ea\u52d5\u751f\u6210\u3055\u308c\u3066\u3044\u307e\u3059\uff09", "C API changes": "C API \u306b\u95a2\u3059\u308b\u5909\u66f4", "Changes in Version %(version)s — %(docstitle)s": "\u30d0\u30fc\u30b8\u30e7\u30f3 %(version)s \u306e\u5909\u66f4\u70b9 — %(docstitle)s", "Collapse sidebar": "\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u305f\u305f\u3080", "Complete Table of Contents": "\u7dcf\u5408\u76ee\u6b21", "Contents": "\u30b3\u30f3\u30c6\u30f3\u30c4", "Copyright": "\u8457\u4f5c\u6a29", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u3053\u306e\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306f <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u3067\u751f\u6210\u3057\u307e\u3057\u305f\u3002", "Expand sidebar": "\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u5c55\u958b", "Full index on one page": "\u7dcf\u7d22\u5f15", "General Index": "\u7dcf\u5408\u7d22\u5f15", "Global Module Index": "\u30e2\u30b8\u30e5\u30fc\u30eb\u7dcf\u7d22\u5f15", "Go": "\u691c\u7d22", "Hide Search Matches": "\u691c\u7d22\u7d50\u679c\u3092\u96a0\u3059", "Index": "\u7d22\u5f15", "Index – %(key)s": "\u7d22\u5f15 – %(key)s", "Index pages by letter": "\u982d\u6587\u5b57\u5225\u7d22\u5f15", "Indices and tables:": "\u7d22\u5f15\u3068\u8868\u4e00\u89a7:", "Last updated on %(last_updated)s.": "\u6700\u7d42\u66f4\u65b0: %(last_updated)s", "Library changes": "\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u95a2\u3059\u308b\u5909\u66f4", "Navigation": "\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3", "Next topic": "\u6b21\u306e\u30c8\u30d4\u30c3\u30af\u3078", "Other changes": "\u305d\u306e\u4ed6\u306e\u5909\u66f4", "Overview": "\u6982\u8981", "Permalink to this definition": "\u3053\u306e\u5b9a\u7fa9\u3078\u306e\u30d1\u30fc\u30de\u30ea\u30f3\u30af", "Permalink to this headline": "\u3053\u306e\u30d8\u30c3\u30c9\u30e9\u30a4\u30f3\u3078\u306e\u30d1\u30fc\u30de\u30ea\u30f3\u30af", "Please activate JavaScript to enable the search\n functionality.": "\u691c\u7d22\u6a5f\u80fd\u3092\u4f7f\u3046\u306b\u306f JavaScript \u3092\u6709\u52b9\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002", "Preparing search...": "\u691c\u7d22\u3092\u6e96\u5099\u3057\u3066\u3044\u307e\u3059...", "Previous topic": "\u524d\u306e\u30c8\u30d4\u30c3\u30af\u3078", "Quick search": "\u30af\u30a4\u30c3\u30af\u691c\u7d22", "Search": "\u691c\u7d22", "Search Page": "\u691c\u7d22\u30da\u30fc\u30b8", "Search Results": "\u691c\u7d22\u7d50\u679c", "Search finished, found %s page(s) matching the search query.": "\u691c\u7d22\u304c\u5b8c\u4e86\u3057\u3001 %s \u30da\u30fc\u30b8\u898b\u3064\u3051\u307e\u3057\u305f\u3002", "Search within %(docstitle)s": "%(docstitle)s \u5185\u3092\u691c\u7d22", "Searching": "\u691c\u7d22\u4e2d", "Searching for multiple words only shows matches that contain\n all words.": "\u8907\u6570\u306e\u5358\u8a9e\u3092\u691c\u7d22\u3059\u308b\u3068\u3001\u6b21\u3092\u542b\u3080\u4e00\u81f4\u306e\u307f\u304c\u8868\u793a\u3055\u308c\u307e\u3059\n \u00a0\u00a0\u00a0 \u3059\u3079\u3066\u306e\u7528\u8a9e\u3002", "Show Source": "\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3092\u8868\u793a", "Table of Contents": "\u76ee\u6b21", "This Page": "\u3053\u306e\u30da\u30fc\u30b8", "Welcome! This is": "Welcome! This is", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u691c\u7d22\u3057\u305f\u6587\u5b57\u5217\u306f\u3069\u306e\u6587\u66f8\u306b\u3082\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u3059\u3079\u3066\u306e\u5358\u8a9e\u304c\u6b63\u78ba\u306b\u8a18\u8ff0\u3055\u308c\u3066\u3044\u308b\u304b\u3001\u3042\u308b\u3044\u306f\u3001\u5341\u5206\u306a\u30ab\u30c6\u30b4\u30ea\u30fc\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u308b\u304b\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002", "all functions, classes, terms": "\u95a2\u6570\u3001\u30af\u30e9\u30b9\u304a\u3088\u3073\u7528\u8a9e\u7dcf\u89a7", "can be huge": "\u5927\u304d\u3044\u5834\u5408\u304c\u3042\u308b\u306e\u3067\u6ce8\u610f", "last updated": "\u6700\u7d42\u66f4\u65b0", "lists all sections and subsections": "\u7ae0\uff0f\u7bc0\u4e00\u89a7", "next chapter": "\u6b21\u306e\u7ae0\u3078", "previous chapter": "\u524d\u306e\u7ae0\u3078", "quick access to all modules": "\u5168\u30e2\u30b8\u30e5\u30fc\u30eb\u65e9\u898b\u8868", "search": "\u691c\u7d22", "search this documentation": "\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u3092\u691c\u7d22", "the documentation for": "the documentation for"}, "plural_expr": "0"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ja", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", in ", + "About these documents": "\u3053\u306e\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306b\u3064\u3044\u3066", + "Automatically generated list of changes in version %(version)s": "\u30d0\u30fc\u30b8\u30e7\u30f3 %(version)s \u306e\u5909\u66f4\u70b9\uff08\u3053\u306e\u30ea\u30b9\u30c8\u306f\u81ea\u52d5\u751f\u6210\u3055\u308c\u3066\u3044\u307e\u3059\uff09", + "C API changes": "C API \u306b\u95a2\u3059\u308b\u5909\u66f4", + "Changes in Version %(version)s — %(docstitle)s": "\u30d0\u30fc\u30b8\u30e7\u30f3 %(version)s \u306e\u5909\u66f4\u70b9 — %(docstitle)s", + "Collapse sidebar": "\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u305f\u305f\u3080", + "Complete Table of Contents": "\u7dcf\u5408\u76ee\u6b21", + "Contents": "\u30b3\u30f3\u30c6\u30f3\u30c4", + "Copyright": "\u8457\u4f5c\u6a29", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u3053\u306e\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306f <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u3067\u751f\u6210\u3057\u307e\u3057\u305f\u3002", + "Expand sidebar": "\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u5c55\u958b", + "Full index on one page": "\u7dcf\u7d22\u5f15", + "General Index": "\u7dcf\u5408\u7d22\u5f15", + "Global Module Index": "\u30e2\u30b8\u30e5\u30fc\u30eb\u7dcf\u7d22\u5f15", + "Go": "\u691c\u7d22", + "Hide Search Matches": "\u691c\u7d22\u7d50\u679c\u3092\u96a0\u3059", + "Index": "\u7d22\u5f15", + "Index – %(key)s": "\u7d22\u5f15 – %(key)s", + "Index pages by letter": "\u982d\u6587\u5b57\u5225\u7d22\u5f15", + "Indices and tables:": "\u7d22\u5f15\u3068\u8868\u4e00\u89a7:", + "Last updated on %(last_updated)s.": "\u6700\u7d42\u66f4\u65b0: %(last_updated)s", + "Library changes": "\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u95a2\u3059\u308b\u5909\u66f4", + "Navigation": "\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3", + "Next topic": "\u6b21\u306e\u30c8\u30d4\u30c3\u30af\u3078", + "Other changes": "\u305d\u306e\u4ed6\u306e\u5909\u66f4", + "Overview": "\u6982\u8981", + "Permalink to this definition": "\u3053\u306e\u5b9a\u7fa9\u3078\u306e\u30d1\u30fc\u30de\u30ea\u30f3\u30af", + "Permalink to this headline": "\u3053\u306e\u30d8\u30c3\u30c9\u30e9\u30a4\u30f3\u3078\u306e\u30d1\u30fc\u30de\u30ea\u30f3\u30af", + "Please activate JavaScript to enable the search\n functionality.": "\u691c\u7d22\u6a5f\u80fd\u3092\u4f7f\u3046\u306b\u306f JavaScript \u3092\u6709\u52b9\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002", + "Preparing search...": "\u691c\u7d22\u3092\u6e96\u5099\u3057\u3066\u3044\u307e\u3059...", + "Previous topic": "\u524d\u306e\u30c8\u30d4\u30c3\u30af\u3078", + "Quick search": "\u30af\u30a4\u30c3\u30af\u691c\u7d22", + "Search": "\u691c\u7d22", + "Search Page": "\u691c\u7d22\u30da\u30fc\u30b8", + "Search Results": "\u691c\u7d22\u7d50\u679c", + "Search finished, found %s page(s) matching the search query.": "\u691c\u7d22\u304c\u5b8c\u4e86\u3057\u3001 %s \u30da\u30fc\u30b8\u898b\u3064\u3051\u307e\u3057\u305f\u3002", + "Search within %(docstitle)s": "%(docstitle)s \u5185\u3092\u691c\u7d22", + "Searching": "\u691c\u7d22\u4e2d", + "Searching for multiple words only shows matches that contain\n all words.": "\u8907\u6570\u306e\u5358\u8a9e\u3092\u691c\u7d22\u3059\u308b\u3068\u3001\u6b21\u3092\u542b\u3080\u4e00\u81f4\u306e\u307f\u304c\u8868\u793a\u3055\u308c\u307e\u3059\n \u00a0\u00a0\u00a0 \u3059\u3079\u3066\u306e\u7528\u8a9e\u3002", + "Show Source": "\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3092\u8868\u793a", + "Table of Contents": "\u76ee\u6b21", + "This Page": "\u3053\u306e\u30da\u30fc\u30b8", + "Welcome! This is": "Welcome! This is", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u691c\u7d22\u3057\u305f\u6587\u5b57\u5217\u306f\u3069\u306e\u6587\u66f8\u306b\u3082\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u3059\u3079\u3066\u306e\u5358\u8a9e\u304c\u6b63\u78ba\u306b\u8a18\u8ff0\u3055\u308c\u3066\u3044\u308b\u304b\u3001\u3042\u308b\u3044\u306f\u3001\u5341\u5206\u306a\u30ab\u30c6\u30b4\u30ea\u30fc\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u308b\u304b\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002", + "all functions, classes, terms": "\u95a2\u6570\u3001\u30af\u30e9\u30b9\u304a\u3088\u3073\u7528\u8a9e\u7dcf\u89a7", + "can be huge": "\u5927\u304d\u3044\u5834\u5408\u304c\u3042\u308b\u306e\u3067\u6ce8\u610f", + "last updated": "\u6700\u7d42\u66f4\u65b0", + "lists all sections and subsections": "\u7ae0\uff0f\u7bc0\u4e00\u89a7", + "next chapter": "\u6b21\u306e\u7ae0\u3078", + "previous chapter": "\u524d\u306e\u7ae0\u3078", + "quick access to all modules": "\u5168\u30e2\u30b8\u30e5\u30fc\u30eb\u65e9\u898b\u8868", + "search": "\u691c\u7d22", + "search this documentation": "\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u3092\u691c\u7d22", + "the documentation for": "the documentation for" + }, + "plural_expr": "0" +});
\ No newline at end of file diff --git a/sphinx/locale/ja/LC_MESSAGES/sphinx.po b/sphinx/locale/ja/LC_MESSAGES/sphinx.po index d9299e58c..1477b3d8a 100644 --- a/sphinx/locale/ja/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ja/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # shirou - しろう <shirou.faw@gmail.com>, 2013 # Akitoshi Ohta <fire.kuma8@gmail.com>, 2011 diff --git a/sphinx/locale/ko/LC_MESSAGES/sphinx.js b/sphinx/locale/ko/LC_MESSAGES/sphinx.js index e0ce4a75c..4be215e23 100644 --- a/sphinx/locale/ko/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ko/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ko", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": ", \ubb38\uc11c - ", "About these documents": "\uc774 \ubb38\uc11c \uc815\ubcf4", "Automatically generated list of changes in version %(version)s": "\ubc84\uc804 %(version)s\uc758 \ubcc0\uacbd \uc0ac\ud56d (\uc774 \ubaa9\ub85d\uc740 \uc790\ub3d9\uc73c\ub85c \uc0dd\uc131\ud569\ub2c8\ub2e4)", "C API changes": "C API\uc5d0 \ub300\ud55c \ubcc0\uacbd", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "\uc0ac\uc774\ub4dc\ubc14 \ub2eb\uae30", "Complete Table of Contents": "\uc885\ud569 \ubaa9\ucc28", "Contents": "\ub0b4\uc6a9", "Copyright": "\uc800\uc791\uad8c", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \ubc84\uc804\uc73c\ub85c \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", "Expand sidebar": "\uc0ac\uc774\ub4dc\ubc14 \uc5f4\uae30", "Full index on one page": "\ud55c \ud398\uc774\uc9c0\uc5d0 \uc804\uccb4 \uc0c9\uc778 \ubcf4\uae30", "General Index": "\uc804\uccb4 \uc0c9\uc778", "Global Module Index": "\ubaa8\ub4c8 \ucd1d \uc0c9\uc778", "Go": "\uc774\ub3d9", "Hide Search Matches": "\uac80\uc0c9 \uacb0\uacfc \uc228\uae30\uae30", "Index": "\uc0c9\uc778", "Index – %(key)s": "", "Index pages by letter": "\uc54c\ud30c\ubcb3\ubcc4 \uc0c9\uc778", "Indices and tables:": "\uc0c9\uc778 \ubc0f \ud45c \ubaa9\ub85d:", "Last updated on %(last_updated)s.": "\ucd5c\uc885 \uc5c5\ub370\uc774\ud2b8: %(last_updated)s", "Library changes": "\ub77c\uc774\ube0c\ub7ec\ub9ac\uc5d0 \ub300\ud55c \ubcc0\uacbd", "Navigation": "\ud0d0\uc0c9", "Next topic": "\ub2e4\uc74c \ud56d\ubaa9", "Other changes": "\ub2e4\ub978 \ubcc0\uacbd \uc0ac\ud56d", "Overview": "\uac1c\uc694", "Permalink to this definition": "\uc815\uc758 \uc8fc\uc18c", "Permalink to this headline": "\uc81c\ubaa9 \uc8fc\uc18c", "Please activate JavaScript to enable the search\n functionality.": "\uac80\uc0c9 \uae30\ub2a5\uc744 \uc0ac\uc6a9\ud558\ub824\uba74 JavaScript\ub97c \ud65c\uc131\ud654\ud558\uc2ed\uc2dc\uc624.", "Preparing search...": "\uac80\uc0c9 \uc900\ube44 \uc911\u2026", "Previous topic": "\uc774\uc804 \ud56d\ubaa9", "Quick search": "\ube60\ub978 \uac80\uc0c9", "Search": "\uac80\uc0c9", "Search Page": "\uac80\uc0c9 \ud398\uc774\uc9c0", "Search Results": "\uac80\uc0c9 \uacb0\uacfc", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "%(docstitle)s\uc5d0\uc11c \ucc3e\uae30", "Searching": "\uac80\uc0c9 \uc911", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\uc18c\uc2a4 \ubcf4\uae30", "Table of Contents": "\ubaa9\ucc28", "This Page": "\ud604\uc7ac \ubb38\uc11c", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "\ud568\uc218, \ud074\ub798\uc2a4 \ubc0f \uc6a9\uc5b4 \uac1c\uad00", "can be huge": "\ud070 \uacbd\uc6b0\uac00 \uc788\uc73c\ubbc0\ub85c \uc8fc\uc758", "last updated": "\ucd5c\uc885 \uc5c5\ub370\uc774\ud2b8", "lists all sections and subsections": "\uc601\uc5ed\ubcc4 \ubaa9\ucc28", "next chapter": "\ub2e4\uc74c \uc7a5", "previous chapter": "\uc774\uc804 \uc7a5", "quick access to all modules": "\ubaa8\ub4e0 \ubaa8\ub4c8 \uc870\uacac\ud45c", "search": "\uac80\uc0c9", "search this documentation": "\ubb38\uc11c \uac80\uc0c9", "the documentation for": ""}, "plural_expr": "0"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ko", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": ", \ubb38\uc11c - ", + "About these documents": "\uc774 \ubb38\uc11c \uc815\ubcf4", + "Automatically generated list of changes in version %(version)s": "\ubc84\uc804 %(version)s\uc758 \ubcc0\uacbd \uc0ac\ud56d (\uc774 \ubaa9\ub85d\uc740 \uc790\ub3d9\uc73c\ub85c \uc0dd\uc131\ud569\ub2c8\ub2e4)", + "C API changes": "C API\uc5d0 \ub300\ud55c \ubcc0\uacbd", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "\uc0ac\uc774\ub4dc\ubc14 \ub2eb\uae30", + "Complete Table of Contents": "\uc885\ud569 \ubaa9\ucc28", + "Contents": "\ub0b4\uc6a9", + "Copyright": "\uc800\uc791\uad8c", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \ubc84\uc804\uc73c\ub85c \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", + "Expand sidebar": "\uc0ac\uc774\ub4dc\ubc14 \uc5f4\uae30", + "Full index on one page": "\ud55c \ud398\uc774\uc9c0\uc5d0 \uc804\uccb4 \uc0c9\uc778 \ubcf4\uae30", + "General Index": "\uc804\uccb4 \uc0c9\uc778", + "Global Module Index": "\ubaa8\ub4c8 \ucd1d \uc0c9\uc778", + "Go": "\uc774\ub3d9", + "Hide Search Matches": "\uac80\uc0c9 \uacb0\uacfc \uc228\uae30\uae30", + "Index": "\uc0c9\uc778", + "Index – %(key)s": "", + "Index pages by letter": "\uc54c\ud30c\ubcb3\ubcc4 \uc0c9\uc778", + "Indices and tables:": "\uc0c9\uc778 \ubc0f \ud45c \ubaa9\ub85d:", + "Last updated on %(last_updated)s.": "\ucd5c\uc885 \uc5c5\ub370\uc774\ud2b8: %(last_updated)s", + "Library changes": "\ub77c\uc774\ube0c\ub7ec\ub9ac\uc5d0 \ub300\ud55c \ubcc0\uacbd", + "Navigation": "\ud0d0\uc0c9", + "Next topic": "\ub2e4\uc74c \ud56d\ubaa9", + "Other changes": "\ub2e4\ub978 \ubcc0\uacbd \uc0ac\ud56d", + "Overview": "\uac1c\uc694", + "Permalink to this definition": "\uc815\uc758 \uc8fc\uc18c", + "Permalink to this headline": "\uc81c\ubaa9 \uc8fc\uc18c", + "Please activate JavaScript to enable the search\n functionality.": "\uac80\uc0c9 \uae30\ub2a5\uc744 \uc0ac\uc6a9\ud558\ub824\uba74 JavaScript\ub97c \ud65c\uc131\ud654\ud558\uc2ed\uc2dc\uc624.", + "Preparing search...": "\uac80\uc0c9 \uc900\ube44 \uc911\u2026", + "Previous topic": "\uc774\uc804 \ud56d\ubaa9", + "Quick search": "\ube60\ub978 \uac80\uc0c9", + "Search": "\uac80\uc0c9", + "Search Page": "\uac80\uc0c9 \ud398\uc774\uc9c0", + "Search Results": "\uac80\uc0c9 \uacb0\uacfc", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "%(docstitle)s\uc5d0\uc11c \ucc3e\uae30", + "Searching": "\uac80\uc0c9 \uc911", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\uc18c\uc2a4 \ubcf4\uae30", + "Table of Contents": "\ubaa9\ucc28", + "This Page": "\ud604\uc7ac \ubb38\uc11c", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "\ud568\uc218, \ud074\ub798\uc2a4 \ubc0f \uc6a9\uc5b4 \uac1c\uad00", + "can be huge": "\ud070 \uacbd\uc6b0\uac00 \uc788\uc73c\ubbc0\ub85c \uc8fc\uc758", + "last updated": "\ucd5c\uc885 \uc5c5\ub370\uc774\ud2b8", + "lists all sections and subsections": "\uc601\uc5ed\ubcc4 \ubaa9\ucc28", + "next chapter": "\ub2e4\uc74c \uc7a5", + "previous chapter": "\uc774\uc804 \uc7a5", + "quick access to all modules": "\ubaa8\ub4e0 \ubaa8\ub4c8 \uc870\uacac\ud45c", + "search": "\uac80\uc0c9", + "search this documentation": "\ubb38\uc11c \uac80\uc0c9", + "the documentation for": "" + }, + "plural_expr": "0" +});
\ No newline at end of file diff --git a/sphinx/locale/ko/LC_MESSAGES/sphinx.po b/sphinx/locale/ko/LC_MESSAGES/sphinx.po index bf3bbe78e..56fff17d1 100644 --- a/sphinx/locale/ko/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ko/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Minho Ryang <minhoryang@gmail.com>, 2019 # YT H <dev@theYT.net>, 2019 diff --git a/sphinx/locale/lt/LC_MESSAGES/sphinx.js b/sphinx/locale/lt/LC_MESSAGES/sphinx.js index 4823a5f3e..aafd97ec2 100644 --- a/sphinx/locale/lt/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/lt/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "lt", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "Apie \u0161iuos dokumentus", "Automatically generated list of changes in version %(version)s": "Automati\u0161kai sugeneruotas pakeitim\u0173 %(version)s versijoje s\u0105ra\u0161as", "C API changes": "C API pakeitimai", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Pasl\u0117pti \u0161onin\u0119 juost\u0105", "Complete Table of Contents": "Pilnas Turinys", "Contents": "Turinys", "Copyright": "Autoriaus teis\u0117s", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Sukurta naudojant <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "I\u0161pl\u0117sti \u0161onin\u0119 juost\u0105", "Full index on one page": "Pilnas indeksas viename puslapyje", "General Index": "Bendras indeksas", "Global Module Index": "Globalus Modulio Indeksas", "Go": "Pirmyn", "Hide Search Matches": "Pasl\u0117pti paie\u0161kos rezultatus", "Index": "Indeksas", "Index – %(key)s": "Indeksas – %(key)s", "Index pages by letter": "Indekso puslapiai pagal raid\u0119", "Indices and tables:": "Indeksai ir lentel\u0117s:", "Last updated on %(last_updated)s.": "Paskutinis atnaujinimas %(last_updated)s.", "Library changes": "Bibliotekos pakeitimai", "Navigation": "Navigacija", "Next topic": "Kita tema", "Other changes": "Kiti pakeitimai", "Overview": "Ap\u017evalga", "Permalink to this definition": "Nuoroda \u012f \u0161\u012f apibr\u0117\u017eim\u0105", "Permalink to this headline": "Nuoroda \u012f \u0161i\u0105 antra\u0161t\u0119", "Please activate JavaScript to enable the search\n functionality.": "Pra\u0161ome aktyvuoti JavaScript, kad veikt\u0173 paie\u0161kos\n funkcionalumas.", "Preparing search...": "", "Previous topic": "Praeita tema", "Quick search": "Greitoji paie\u0161ka", "Search": "Paie\u0161ka", "Search Page": "Paie\u0161kos puslapis", "Search Results": "Paie\u0161kos rezultatai", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "Ie\u0161koti tarp %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Rodyti pirmin\u012f kod\u0105", "Table of Contents": "", "This Page": "\u0160is puslapis", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "visos funkcijos, klas\u0117s ir terminai", "can be huge": "gali b\u016bti didelis", "last updated": "", "lists all sections and subsections": "sura\u0161yti visus skyrius ir poskyrius", "next chapter": "kita dalis", "previous chapter": "praeita dalis", "quick access to all modules": "greitas vis\u0173 moduli\u0173 pasiekimas", "search": "ie\u0161koti", "search this documentation": "ie\u0161koti \u0161iame dokumente", "the documentation for": ""}, "plural_expr": "(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "lt", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "Apie \u0161iuos dokumentus", + "Automatically generated list of changes in version %(version)s": "Automati\u0161kai sugeneruotas pakeitim\u0173 %(version)s versijoje s\u0105ra\u0161as", + "C API changes": "C API pakeitimai", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Pasl\u0117pti \u0161onin\u0119 juost\u0105", + "Complete Table of Contents": "Pilnas Turinys", + "Contents": "Turinys", + "Copyright": "Autoriaus teis\u0117s", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Sukurta naudojant <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "I\u0161pl\u0117sti \u0161onin\u0119 juost\u0105", + "Full index on one page": "Pilnas indeksas viename puslapyje", + "General Index": "Bendras indeksas", + "Global Module Index": "Globalus Modulio Indeksas", + "Go": "Pirmyn", + "Hide Search Matches": "Pasl\u0117pti paie\u0161kos rezultatus", + "Index": "Indeksas", + "Index – %(key)s": "Indeksas – %(key)s", + "Index pages by letter": "Indekso puslapiai pagal raid\u0119", + "Indices and tables:": "Indeksai ir lentel\u0117s:", + "Last updated on %(last_updated)s.": "Paskutinis atnaujinimas %(last_updated)s.", + "Library changes": "Bibliotekos pakeitimai", + "Navigation": "Navigacija", + "Next topic": "Kita tema", + "Other changes": "Kiti pakeitimai", + "Overview": "Ap\u017evalga", + "Permalink to this definition": "Nuoroda \u012f \u0161\u012f apibr\u0117\u017eim\u0105", + "Permalink to this headline": "Nuoroda \u012f \u0161i\u0105 antra\u0161t\u0119", + "Please activate JavaScript to enable the search\n functionality.": "Pra\u0161ome aktyvuoti JavaScript, kad veikt\u0173 paie\u0161kos\n funkcionalumas.", + "Preparing search...": "", + "Previous topic": "Praeita tema", + "Quick search": "Greitoji paie\u0161ka", + "Search": "Paie\u0161ka", + "Search Page": "Paie\u0161kos puslapis", + "Search Results": "Paie\u0161kos rezultatai", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "Ie\u0161koti tarp %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Rodyti pirmin\u012f kod\u0105", + "Table of Contents": "", + "This Page": "\u0160is puslapis", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "visos funkcijos, klas\u0117s ir terminai", + "can be huge": "gali b\u016bti didelis", + "last updated": "", + "lists all sections and subsections": "sura\u0161yti visus skyrius ir poskyrius", + "next chapter": "kita dalis", + "previous chapter": "praeita dalis", + "quick access to all modules": "greitas vis\u0173 moduli\u0173 pasiekimas", + "search": "ie\u0161koti", + "search this documentation": "ie\u0161koti \u0161iame dokumente", + "the documentation for": "" + }, + "plural_expr": "(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3)" +});
\ No newline at end of file diff --git a/sphinx/locale/lt/LC_MESSAGES/sphinx.po b/sphinx/locale/lt/LC_MESSAGES/sphinx.po index fbf5b0a1d..4df91eb54 100644 --- a/sphinx/locale/lt/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/lt/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # DALIUS DOBRAVOLSKAS <DALIUS@SANDBOX.LT>, 2010 msgid "" diff --git a/sphinx/locale/lv/LC_MESSAGES/sphinx.js b/sphinx/locale/lv/LC_MESSAGES/sphinx.js index b609e2aef..7d750649d 100644 --- a/sphinx/locale/lv/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/lv/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "lv", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "Par \u0161iem dokumentiem", "Automatically generated list of changes in version %(version)s": "Autom\u0101tiski sagatavots izmai\u0146u saraksts versijai %(version)s", "C API changes": "Izmai\u0146as iek\u0161 C API", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Sav\u0113rst s\u0101njoslu", "Complete Table of Contents": "Pilns saturs", "Contents": "Saturs", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Sagatavots izmantojot <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Izplest s\u0101njoslu", "Full index on one page": "Pilns indekss vien\u0101 lappus\u0113", "General Index": "Visp\u0101r\u0113js indekss", "Global Module Index": "Visp\u0101r\u0113js modu\u013cu indekss", "Go": "Izpild\u012bt", "Hide Search Matches": "Pasl\u0113pt atlases v\u0101rdus", "Index": "Indekss", "Index – %(key)s": "Indekss – %(key)s", "Index pages by letter": "Lappu\u0161u indekss p\u0113c burtiem", "Indices and tables:": "Indeksi un tabulas:", "Last updated on %(last_updated)s.": "P\u0113d\u0113jas izmai\u0146as %(last_updated)s.", "Library changes": "Bibliot\u0113kas izmai\u0146as", "Navigation": "Navig\u0101cija", "Next topic": "n\u0101ko\u0161a t\u0113ma", "Other changes": "Citas izmai\u0146as", "Overview": "Apskats", "Permalink to this definition": "Past\u0101v\u012bga nor\u0101de uz \u0161o defin\u012bciju", "Permalink to this headline": "Past\u0101v\u012bga nor\u0101de \u0161o virsrakstu", "Please activate JavaScript to enable the search\n functionality.": "Lai iesp\u0113jotu mekl\u0113\u0161anu, l\u016bdzu aktiviz\u0113t JavaScript.", "Preparing search...": "", "Previous topic": "iepriek\u0161\u0113ja t\u0113ma", "Quick search": "\u0100tra mekl\u0113\u0161ana", "Search": "Mekl\u0113t", "Search Page": "Atlases lapa", "Search Results": "Atlases rezult\u0101ti", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "Mekl\u0113t iek\u0161 %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "R\u0101d\u012bt izejas tekstu", "Table of Contents": "", "This Page": "\u0160\u012b lappuse", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "visas funkcijas, klases un termini", "can be huge": "var b\u016bt milz\u012bgs", "last updated": "", "lists all sections and subsections": "r\u0101da visas sekcijas un apak\u0161sekcijas", "next chapter": "n\u0101ko\u0161a sada\u013ca", "previous chapter": "iepriek\u0161\u0113ja sada\u013ca", "quick access to all modules": "\u0101tra piek\u013cuve visiem moduliem", "search": "mekl\u0113t", "search this documentation": "mekl\u0113t \u0161aj\u0101 dokument\u0101cij\u0101", "the documentation for": ""}, "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "lv", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "Par \u0161iem dokumentiem", + "Automatically generated list of changes in version %(version)s": "Autom\u0101tiski sagatavots izmai\u0146u saraksts versijai %(version)s", + "C API changes": "Izmai\u0146as iek\u0161 C API", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Sav\u0113rst s\u0101njoslu", + "Complete Table of Contents": "Pilns saturs", + "Contents": "Saturs", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Sagatavots izmantojot <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Izplest s\u0101njoslu", + "Full index on one page": "Pilns indekss vien\u0101 lappus\u0113", + "General Index": "Visp\u0101r\u0113js indekss", + "Global Module Index": "Visp\u0101r\u0113js modu\u013cu indekss", + "Go": "Izpild\u012bt", + "Hide Search Matches": "Pasl\u0113pt atlases v\u0101rdus", + "Index": "Indekss", + "Index – %(key)s": "Indekss – %(key)s", + "Index pages by letter": "Lappu\u0161u indekss p\u0113c burtiem", + "Indices and tables:": "Indeksi un tabulas:", + "Last updated on %(last_updated)s.": "P\u0113d\u0113jas izmai\u0146as %(last_updated)s.", + "Library changes": "Bibliot\u0113kas izmai\u0146as", + "Navigation": "Navig\u0101cija", + "Next topic": "n\u0101ko\u0161a t\u0113ma", + "Other changes": "Citas izmai\u0146as", + "Overview": "Apskats", + "Permalink to this definition": "Past\u0101v\u012bga nor\u0101de uz \u0161o defin\u012bciju", + "Permalink to this headline": "Past\u0101v\u012bga nor\u0101de \u0161o virsrakstu", + "Please activate JavaScript to enable the search\n functionality.": "Lai iesp\u0113jotu mekl\u0113\u0161anu, l\u016bdzu aktiviz\u0113t JavaScript.", + "Preparing search...": "", + "Previous topic": "iepriek\u0161\u0113ja t\u0113ma", + "Quick search": "\u0100tra mekl\u0113\u0161ana", + "Search": "Mekl\u0113t", + "Search Page": "Atlases lapa", + "Search Results": "Atlases rezult\u0101ti", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "Mekl\u0113t iek\u0161 %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "R\u0101d\u012bt izejas tekstu", + "Table of Contents": "", + "This Page": "\u0160\u012b lappuse", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "visas funkcijas, klases un termini", + "can be huge": "var b\u016bt milz\u012bgs", + "last updated": "", + "lists all sections and subsections": "r\u0101da visas sekcijas un apak\u0161sekcijas", + "next chapter": "n\u0101ko\u0161a sada\u013ca", + "previous chapter": "iepriek\u0161\u0113ja sada\u013ca", + "quick access to all modules": "\u0101tra piek\u013cuve visiem moduliem", + "search": "mekl\u0113t", + "search this documentation": "mekl\u0113t \u0161aj\u0101 dokument\u0101cij\u0101", + "the documentation for": "" + }, + "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2)" +});
\ No newline at end of file diff --git a/sphinx/locale/lv/LC_MESSAGES/sphinx.po b/sphinx/locale/lv/LC_MESSAGES/sphinx.po index a3968756d..ca8ef8240 100644 --- a/sphinx/locale/lv/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/lv/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/mk/LC_MESSAGES/sphinx.js b/sphinx/locale/mk/LC_MESSAGES/sphinx.js index 317165e40..e0349d176 100644 --- a/sphinx/locale/mk/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/mk/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "mk", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "\u0413\u043b\u0430\u0432\u043d\u0430 \u0441\u043e\u0434\u0440\u0436\u0438\u043d\u0430", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n % 10 == 1 && n % 100 != 11) ? 0 : 1"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "mk", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "\u0413\u043b\u0430\u0432\u043d\u0430 \u0441\u043e\u0434\u0440\u0436\u0438\u043d\u0430", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n % 10 == 1 && n % 100 != 11) ? 0 : 1" +});
\ No newline at end of file diff --git a/sphinx/locale/mk/LC_MESSAGES/sphinx.po b/sphinx/locale/mk/LC_MESSAGES/sphinx.po index 5543d45fd..397828d91 100644 --- a/sphinx/locale/mk/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/mk/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Vasil Vangelovski <vvangelovski@gmail.com>, 2013 msgid "" diff --git a/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js b/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js index 8e6b8f4ea..a2f0f5073 100644 --- a/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "nb_NO", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "Om disse dokumenter", "Automatically generated list of changes in version %(version)s": "Automatisk generert liste over endringer i versjon %(version)s", "C API changes": "Endringer i C API", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Skjul sidepanelet", "Complete Table of Contents": "Komplett Innholdsfortegnelse", "Contents": "Innhold", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Lagd med <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Utvid sidepanelet", "Full index on one page": "Hele innholdsfortegnelsen p\u00e5 en side", "General Index": "Hovedindex", "Global Module Index": "Global Modulindex", "Go": "G\u00e5", "Hide Search Matches": "Skjul s\u00f8keresultat", "Index": "Index", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "Innholdsfortegnelse per bokstav", "Indices and tables:": "Index og tabeller", "Last updated on %(last_updated)s.": "Sist oppdatert %(last_updated)s.", "Library changes": "Endringer i biblioteket", "Navigation": "Navigering", "Next topic": "Neste emne", "Other changes": "Andre endringer", "Overview": "Oversikt", "Permalink to this definition": "Permalink til denne definisjonen", "Permalink to this headline": "Permalink til denne oversikten", "Please activate JavaScript to enable the search\n functionality.": "Vennligst aktiver JavaScript for \u00e5 aktivere s\u00f8k.", "Preparing search...": "", "Previous topic": "Forrige tittel", "Quick search": "Hurtigs\u00f8k", "Search": "S\u00f8k", "Search Page": "S\u00f8keside", "Search Results": "S\u00f8keresultat", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "S\u00f8k blant %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Vis kildekode", "Table of Contents": "", "This Page": "Denne siden", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "alla funksjoner, klasser, vilk\u00e5r", "can be huge": "kan bli stor", "last updated": "", "lists all sections and subsections": "liste over alle paragrafer og underparagrafer", "next chapter": "neste kapittel", "previous chapter": "Forrige kapittel", "quick access to all modules": "snarvei til alle moduler", "search": "s\u00f8k", "search this documentation": "s\u00f8k i dette dokumentet", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "nb_NO", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "Om disse dokumenter", + "Automatically generated list of changes in version %(version)s": "Automatisk generert liste over endringer i versjon %(version)s", + "C API changes": "Endringer i C API", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Skjul sidepanelet", + "Complete Table of Contents": "Komplett Innholdsfortegnelse", + "Contents": "Innhold", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Lagd med <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Utvid sidepanelet", + "Full index on one page": "Hele innholdsfortegnelsen p\u00e5 en side", + "General Index": "Hovedindex", + "Global Module Index": "Global Modulindex", + "Go": "G\u00e5", + "Hide Search Matches": "Skjul s\u00f8keresultat", + "Index": "Index", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "Innholdsfortegnelse per bokstav", + "Indices and tables:": "Index og tabeller", + "Last updated on %(last_updated)s.": "Sist oppdatert %(last_updated)s.", + "Library changes": "Endringer i biblioteket", + "Navigation": "Navigering", + "Next topic": "Neste emne", + "Other changes": "Andre endringer", + "Overview": "Oversikt", + "Permalink to this definition": "Permalink til denne definisjonen", + "Permalink to this headline": "Permalink til denne oversikten", + "Please activate JavaScript to enable the search\n functionality.": "Vennligst aktiver JavaScript for \u00e5 aktivere s\u00f8k.", + "Preparing search...": "", + "Previous topic": "Forrige tittel", + "Quick search": "Hurtigs\u00f8k", + "Search": "S\u00f8k", + "Search Page": "S\u00f8keside", + "Search Results": "S\u00f8keresultat", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "S\u00f8k blant %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Vis kildekode", + "Table of Contents": "", + "This Page": "Denne siden", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "alla funksjoner, klasser, vilk\u00e5r", + "can be huge": "kan bli stor", + "last updated": "", + "lists all sections and subsections": "liste over alle paragrafer og underparagrafer", + "next chapter": "neste kapittel", + "previous chapter": "Forrige kapittel", + "quick access to all modules": "snarvei til alle moduler", + "search": "s\u00f8k", + "search this documentation": "s\u00f8k i dette dokumentet", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po b/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po index b061b0361..05fe2c92c 100644 --- a/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/ne/LC_MESSAGES/sphinx.js b/sphinx/locale/ne/LC_MESSAGES/sphinx.js index 01f0dd04d..3c7e6f94a 100644 --- a/sphinx/locale/ne/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ne/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ne", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "\u092f\u0940 \u0921\u0915\u0941\u092e\u0947\u0928\u094d\u091f\u0939\u0930\u0941\u0915\u094b \u092c\u093e\u0930\u0947\u092e\u093e", "Automatically generated list of changes in version %(version)s": "\u092d\u0930\u094d\u0938\u0928 %(version)s \u092e\u093e \u092d\u090f\u0915\u093e \u092b\u0930\u0915 \u0939\u0930\u0941 \u0906\u092b\u0948 \u091c\u0947\u0928\u0947\u0930\u0947\u091f \u092d\u090f ", "C API changes": "C API \u0915\u093e \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928\u0939\u0930\u0941 ", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "\u0938\u093e\u0907\u0921\u092c\u0930 \u0938\u093e\u0928\u094b \u092c\u0928\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d", "Complete Table of Contents": "\u092a\u0941\u0930\u093e \u0935\u093f\u0937\u092f\u0938\u0942\u091a\u0940", "Contents": "\u0935\u093f\u0937\u092f\u0938\u0942\u091a\u0940", "Copyright": "\u0915\u092a\u093f\u0930\u093e\u0907\u091f ", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "\u0938\u093e\u0907\u0921\u092c\u0930 \u0920\u0941\u0932\u094b \u092c\u0928\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d", "Full index on one page": "\u092a\u0941\u0930\u093e \u0905\u0928\u0941\u0938\u0941\u091a\u0940 \u090f\u0915\u0948 \u092a\u093e\u0928\u093e\u092e\u093e", "General Index": "\u0938\u093e\u092e\u093e\u0928\u094d\u092f \u0905\u0928\u0941\u0938\u0941\u091a\u0940", "Global Module Index": "\u0917\u094d\u0932\u094b\u092c\u0932 \u092e\u0921\u0941\u0932 \u0905\u0928\u0941\u0938\u0941\u091a\u0940", "Go": "\u091c\u093e\u0928\u0941\u0939\u094b\u0938\u094d", "Hide Search Matches": "\u0916\u094b\u091c\u0947\u0915\u094b \u0928\u0924\u093f\u091c\u093e\u0939\u0930\u0941 \u0932\u0941\u0915\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d", "Index": "\u0905\u0928\u0941\u0938\u0941\u091a\u0940", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "\u0905\u0915\u094d\u0937\u0930 \u0905\u0928\u0941\u0938\u093e\u0930 \u0905\u0928\u0941\u0938\u0941\u091a\u0940\u0915\u093e \u092a\u093e\u0928\u093e", "Indices and tables:": "\u0907\u0928\u094d\u0921\u0940\u0938\u0940\u0938\u094d\u0938 \u0930 \u0924\u0932\u093f\u0915\u093e", "Last updated on %(last_updated)s.": "\u092f\u094b \u092d\u0928\u094d\u0926\u093e \u0905\u0917\u093e\u0921\u0940 %(last_updated)s \u092e\u093e \u0905\u092a\u0921\u0947\u091f \u092d\u090f\u0915\u094b", "Library changes": "\u0932\u093e\u0908\u092c\u094d\u0930\u0947\u0930\u0940\u0915\u093e \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928\u0939\u0930\u0941", "Navigation": "\u0928\u0947\u092d\u093f\u0917\u0947\u0938\u0928 ", "Next topic": "\u092a\u091b\u093f\u0932\u094d\u0932\u094b \u0935\u093f\u0937\u092f", "Other changes": "\u0905\u0930\u0941 \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928\u0939\u0930\u0941 ", "Overview": "\u092a\u0941\u0928\u0930\u093e\u0935\u0932\u094b\u0915\u0928 ", "Permalink to this definition": "\u092f\u094b \u0905\u0930\u094d\u0925\u0915\u094b \u0932\u093e\u0917\u093f \u092a\u0930\u094d\u092e\u093e\u0932\u093f\u0928\u094d\u0915", "Permalink to this headline": "\u092f\u094b \u0936\u093f\u0930\u094d\u0937\u0915\u0915\u094b \u0932\u093e\u0917\u093f \u092a\u0930\u094d\u092e\u093e\u0932\u093f\u0928\u094d\u0915 \u0964 ", "Please activate JavaScript to enable the search\n functionality.": "\u0916\u094b\u091c\u094d\u0928\u0947 \u0915\u093e\u0930\u094d\u092f \u0906\u0917\u093e\u0921\u0940 \u092c\u0922\u093e\u0909\u0928\u0915\u094b \u0932\u093e\u0917\u093f \u091c\u093e\u092d\u093e\u0938\u094d\u0915\u0943\u092a\u094d\u091f \u091a\u0932\u093e\u0908\u0926\u093f\u0928\u0941\u0939\u094b\u0938 ", "Preparing search...": "", "Previous topic": "\u0905\u0918\u093f\u0932\u094d\u0932\u094b \u0935\u093f\u0937\u092f ", "Quick search": "\u091b\u093f\u091f\u094d\u091f\u094b \u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d", "Search": "\u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d ", "Search Page": "\u092a\u093e\u0928\u093e\u092e\u093e \u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d", "Search Results": "\u0916\u094b\u091c\u0947\u0915\u094b \u0928\u0924\u093f\u091c\u093e", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u0938\u094d\u0930\u094b\u0924 \u0926\u0947\u0916\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d ", "Table of Contents": "", "This Page": "\u092f\u094b \u092a\u093e\u0928\u093e", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "\u0938\u092c\u0948 \u092b\u0928\u094d\u0915\u094d\u0938\u0928\u0938\u094d, \u0915\u0915\u094d\u0937\u093e\u0939\u0930\u0942 \u0930 \u091f\u0930\u094d\u092e\u0938\u094d", "can be huge": "\u0927\u0947\u0930\u0948 \u0920\u0941\u0932\u094b \u0939\u0941\u0928 \u0938\u0915\u094d\u091b", "last updated": "", "lists all sections and subsections": "\u0938\u092c\u0948 \u0938\u0947\u0915\u094d\u0938\u0928 \u0930 \u0938\u0935\u0938\u0947\u0915\u094d\u0938\u0928 \u0926\u0947\u0916\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d", "next chapter": "\u092a\u091b\u093f\u0932\u094d\u0932\u094b \u0916\u0928\u094d\u0921", "previous chapter": "\u0905\u0918\u093f\u0932\u094d\u0932\u094b \u0916\u0928\u094d\u0921", "quick access to all modules": "\u0938\u092c\u0948 \u092e\u094b\u0926\u0941\u0932\u0947\u0938\u092e\u093e \u091b\u093f\u091f\u0948 \u091c\u093e\u0928\u0941\u0939\u094b\u0938\u094d", "search": "\u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d", "search this documentation": "\u092f\u094b \u0921\u0915\u0941\u092e\u0947\u0928\u094d\u091f \u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ne", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "\u092f\u0940 \u0921\u0915\u0941\u092e\u0947\u0928\u094d\u091f\u0939\u0930\u0941\u0915\u094b \u092c\u093e\u0930\u0947\u092e\u093e", + "Automatically generated list of changes in version %(version)s": "\u092d\u0930\u094d\u0938\u0928 %(version)s \u092e\u093e \u092d\u090f\u0915\u093e \u092b\u0930\u0915 \u0939\u0930\u0941 \u0906\u092b\u0948 \u091c\u0947\u0928\u0947\u0930\u0947\u091f \u092d\u090f ", + "C API changes": "C API \u0915\u093e \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928\u0939\u0930\u0941 ", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "\u0938\u093e\u0907\u0921\u092c\u0930 \u0938\u093e\u0928\u094b \u092c\u0928\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d", + "Complete Table of Contents": "\u092a\u0941\u0930\u093e \u0935\u093f\u0937\u092f\u0938\u0942\u091a\u0940", + "Contents": "\u0935\u093f\u0937\u092f\u0938\u0942\u091a\u0940", + "Copyright": "\u0915\u092a\u093f\u0930\u093e\u0907\u091f ", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "\u0938\u093e\u0907\u0921\u092c\u0930 \u0920\u0941\u0932\u094b \u092c\u0928\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d", + "Full index on one page": "\u092a\u0941\u0930\u093e \u0905\u0928\u0941\u0938\u0941\u091a\u0940 \u090f\u0915\u0948 \u092a\u093e\u0928\u093e\u092e\u093e", + "General Index": "\u0938\u093e\u092e\u093e\u0928\u094d\u092f \u0905\u0928\u0941\u0938\u0941\u091a\u0940", + "Global Module Index": "\u0917\u094d\u0932\u094b\u092c\u0932 \u092e\u0921\u0941\u0932 \u0905\u0928\u0941\u0938\u0941\u091a\u0940", + "Go": "\u091c\u093e\u0928\u0941\u0939\u094b\u0938\u094d", + "Hide Search Matches": "\u0916\u094b\u091c\u0947\u0915\u094b \u0928\u0924\u093f\u091c\u093e\u0939\u0930\u0941 \u0932\u0941\u0915\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d", + "Index": "\u0905\u0928\u0941\u0938\u0941\u091a\u0940", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "\u0905\u0915\u094d\u0937\u0930 \u0905\u0928\u0941\u0938\u093e\u0930 \u0905\u0928\u0941\u0938\u0941\u091a\u0940\u0915\u093e \u092a\u093e\u0928\u093e", + "Indices and tables:": "\u0907\u0928\u094d\u0921\u0940\u0938\u0940\u0938\u094d\u0938 \u0930 \u0924\u0932\u093f\u0915\u093e", + "Last updated on %(last_updated)s.": "\u092f\u094b \u092d\u0928\u094d\u0926\u093e \u0905\u0917\u093e\u0921\u0940 %(last_updated)s \u092e\u093e \u0905\u092a\u0921\u0947\u091f \u092d\u090f\u0915\u094b", + "Library changes": "\u0932\u093e\u0908\u092c\u094d\u0930\u0947\u0930\u0940\u0915\u093e \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928\u0939\u0930\u0941", + "Navigation": "\u0928\u0947\u092d\u093f\u0917\u0947\u0938\u0928 ", + "Next topic": "\u092a\u091b\u093f\u0932\u094d\u0932\u094b \u0935\u093f\u0937\u092f", + "Other changes": "\u0905\u0930\u0941 \u092a\u0930\u093f\u0935\u0930\u094d\u0924\u0928\u0939\u0930\u0941 ", + "Overview": "\u092a\u0941\u0928\u0930\u093e\u0935\u0932\u094b\u0915\u0928 ", + "Permalink to this definition": "\u092f\u094b \u0905\u0930\u094d\u0925\u0915\u094b \u0932\u093e\u0917\u093f \u092a\u0930\u094d\u092e\u093e\u0932\u093f\u0928\u094d\u0915", + "Permalink to this headline": "\u092f\u094b \u0936\u093f\u0930\u094d\u0937\u0915\u0915\u094b \u0932\u093e\u0917\u093f \u092a\u0930\u094d\u092e\u093e\u0932\u093f\u0928\u094d\u0915 \u0964 ", + "Please activate JavaScript to enable the search\n functionality.": "\u0916\u094b\u091c\u094d\u0928\u0947 \u0915\u093e\u0930\u094d\u092f \u0906\u0917\u093e\u0921\u0940 \u092c\u0922\u093e\u0909\u0928\u0915\u094b \u0932\u093e\u0917\u093f \u091c\u093e\u092d\u093e\u0938\u094d\u0915\u0943\u092a\u094d\u091f \u091a\u0932\u093e\u0908\u0926\u093f\u0928\u0941\u0939\u094b\u0938 ", + "Preparing search...": "", + "Previous topic": "\u0905\u0918\u093f\u0932\u094d\u0932\u094b \u0935\u093f\u0937\u092f ", + "Quick search": "\u091b\u093f\u091f\u094d\u091f\u094b \u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d", + "Search": "\u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d ", + "Search Page": "\u092a\u093e\u0928\u093e\u092e\u093e \u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d", + "Search Results": "\u0916\u094b\u091c\u0947\u0915\u094b \u0928\u0924\u093f\u091c\u093e", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u0938\u094d\u0930\u094b\u0924 \u0926\u0947\u0916\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d ", + "Table of Contents": "", + "This Page": "\u092f\u094b \u092a\u093e\u0928\u093e", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "\u0938\u092c\u0948 \u092b\u0928\u094d\u0915\u094d\u0938\u0928\u0938\u094d, \u0915\u0915\u094d\u0937\u093e\u0939\u0930\u0942 \u0930 \u091f\u0930\u094d\u092e\u0938\u094d", + "can be huge": "\u0927\u0947\u0930\u0948 \u0920\u0941\u0932\u094b \u0939\u0941\u0928 \u0938\u0915\u094d\u091b", + "last updated": "", + "lists all sections and subsections": "\u0938\u092c\u0948 \u0938\u0947\u0915\u094d\u0938\u0928 \u0930 \u0938\u0935\u0938\u0947\u0915\u094d\u0938\u0928 \u0926\u0947\u0916\u093e\u0909\u0928\u0941\u0939\u094b\u0938\u094d", + "next chapter": "\u092a\u091b\u093f\u0932\u094d\u0932\u094b \u0916\u0928\u094d\u0921", + "previous chapter": "\u0905\u0918\u093f\u0932\u094d\u0932\u094b \u0916\u0928\u094d\u0921", + "quick access to all modules": "\u0938\u092c\u0948 \u092e\u094b\u0926\u0941\u0932\u0947\u0938\u092e\u093e \u091b\u093f\u091f\u0948 \u091c\u093e\u0928\u0941\u0939\u094b\u0938\u094d", + "search": "\u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d", + "search this documentation": "\u092f\u094b \u0921\u0915\u0941\u092e\u0947\u0928\u094d\u091f \u0916\u094b\u091c\u094d\u0928\u0941\u0939\u094b\u0938\u094d", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/ne/LC_MESSAGES/sphinx.po b/sphinx/locale/ne/LC_MESSAGES/sphinx.po index 46590097d..22e4ef626 100644 --- a/sphinx/locale/ne/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ne/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2011 # Takeshi KOMIYA <i.tkomiya@gmail.com>, 2016 diff --git a/sphinx/locale/nl/LC_MESSAGES/sphinx.js b/sphinx/locale/nl/LC_MESSAGES/sphinx.js index 78f190a3b..1d7cf6565 100644 --- a/sphinx/locale/nl/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/nl/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "nl", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", in", "About these documents": "Over deze documenten", "Automatically generated list of changes in version %(version)s": "Automatisch gegenereerde lijst van veranderingen in versie %(version)s", "C API changes": "Veranderingen in de C-API", "Changes in Version %(version)s — %(docstitle)s": "Wijzigingen in Versie %(version)s — %(docstitle)s", "Collapse sidebar": "Zijpaneel inklappen", "Complete Table of Contents": "Volledige inhoudsopgave", "Contents": "Inhoudsopgave", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Aangemaakt met <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Zijpaneel uitklappen", "Full index on one page": "Volledige index op \u00e9\u00e9n pagina", "General Index": "Algemene index", "Global Module Index": "Globale Module-index", "Go": "Zoek", "Hide Search Matches": "Zoekresultaten verbergen", "Index": "Index", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "Index pagineerd per letter", "Indices and tables:": "Indices en tabellen:", "Last updated on %(last_updated)s.": "Laatste aanpassing op %(last_updated)s.", "Library changes": "Veranderingen in de bibliotheek", "Navigation": "Navigatie", "Next topic": "Volgend onderwerp", "Other changes": "Andere veranderingen", "Overview": "Overzicht", "Permalink to this definition": "Permalink naar deze definitie", "Permalink to this headline": "Permalink naar deze titel", "Please activate JavaScript to enable the search\n functionality.": "Activeer JavaSscript om de zoekfunctionaliteit in te schakelen.", "Preparing search...": "Zoeken aan het voorbereiden...", "Previous topic": "Vorig onderwerp", "Quick search": "Snel zoeken", "Search": "Zoeken", "Search Page": "Zoekpagina", "Search Results": "Zoekresultaten", "Search finished, found %s page(s) matching the search query.": "Zoekopdracht voltooid, %s pagaina(s) gevonden die overeenkomen met de zoekterm.", "Search within %(docstitle)s": "Zoeken in %(docstitle)s", "Searching": "Bezig met zoeken", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Broncode weergeven", "Table of Contents": "", "This Page": "Deze pagina", "Welcome! This is": "Welkom! Dit is", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Uw zoekopdracht leverde geen resultaten op. Zorg ervoor dat alle woorden juist zijn gespeld en dat u voldoende categorie\u00ebn hebt geselecteerd.", "all functions, classes, terms": "alle functies, klasses en begrippen", "can be huge": "kan heel groot zijn", "last updated": "laatst bijgewerkt", "lists all sections and subsections": "geeft alle secties en subsecties weer", "next chapter": "volgend hoofdstuk", "previous chapter": "vorig hoofdstuk", "quick access to all modules": "sneltoegang naar alle modules", "search": "zoeken", "search this documentation": "zoeken in deze documentatie", "the documentation for": "de documentatie voor"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "nl", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", in", + "About these documents": "Over deze documenten", + "Automatically generated list of changes in version %(version)s": "Automatisch gegenereerde lijst van veranderingen in versie %(version)s", + "C API changes": "Veranderingen in de C-API", + "Changes in Version %(version)s — %(docstitle)s": "Wijzigingen in Versie %(version)s — %(docstitle)s", + "Collapse sidebar": "Zijpaneel inklappen", + "Complete Table of Contents": "Volledige inhoudsopgave", + "Contents": "Inhoudsopgave", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Aangemaakt met <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Zijpaneel uitklappen", + "Full index on one page": "Volledige index op \u00e9\u00e9n pagina", + "General Index": "Algemene index", + "Global Module Index": "Globale Module-index", + "Go": "Zoek", + "Hide Search Matches": "Zoekresultaten verbergen", + "Index": "Index", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "Index pagineerd per letter", + "Indices and tables:": "Indices en tabellen:", + "Last updated on %(last_updated)s.": "Laatste aanpassing op %(last_updated)s.", + "Library changes": "Veranderingen in de bibliotheek", + "Navigation": "Navigatie", + "Next topic": "Volgend onderwerp", + "Other changes": "Andere veranderingen", + "Overview": "Overzicht", + "Permalink to this definition": "Permalink naar deze definitie", + "Permalink to this headline": "Permalink naar deze titel", + "Please activate JavaScript to enable the search\n functionality.": "Activeer JavaSscript om de zoekfunctionaliteit in te schakelen.", + "Preparing search...": "Zoeken aan het voorbereiden...", + "Previous topic": "Vorig onderwerp", + "Quick search": "Snel zoeken", + "Search": "Zoeken", + "Search Page": "Zoekpagina", + "Search Results": "Zoekresultaten", + "Search finished, found %s page(s) matching the search query.": "Zoekopdracht voltooid, %s pagaina(s) gevonden die overeenkomen met de zoekterm.", + "Search within %(docstitle)s": "Zoeken in %(docstitle)s", + "Searching": "Bezig met zoeken", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Broncode weergeven", + "Table of Contents": "", + "This Page": "Deze pagina", + "Welcome! This is": "Welkom! Dit is", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Uw zoekopdracht leverde geen resultaten op. Zorg ervoor dat alle woorden juist zijn gespeld en dat u voldoende categorie\u00ebn hebt geselecteerd.", + "all functions, classes, terms": "alle functies, klasses en begrippen", + "can be huge": "kan heel groot zijn", + "last updated": "laatst bijgewerkt", + "lists all sections and subsections": "geeft alle secties en subsecties weer", + "next chapter": "volgend hoofdstuk", + "previous chapter": "vorig hoofdstuk", + "quick access to all modules": "sneltoegang naar alle modules", + "search": "zoeken", + "search this documentation": "zoeken in deze documentatie", + "the documentation for": "de documentatie voor" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/nl/LC_MESSAGES/sphinx.po b/sphinx/locale/nl/LC_MESSAGES/sphinx.po index d5eb16c6f..4bdf9f43b 100644 --- a/sphinx/locale/nl/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/nl/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Bram Geron, 2017 # brechtm, 2016 diff --git a/sphinx/locale/pl/LC_MESSAGES/sphinx.js b/sphinx/locale/pl/LC_MESSAGES/sphinx.js index 4d22d3c91..152d744d0 100644 --- a/sphinx/locale/pl/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/pl/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "pl", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", w ", "About these documents": "O tych dokumentach", "Automatically generated list of changes in version %(version)s": "Automatycznie wygenerowana lista zmian w wersji %(version)s", "C API changes": "Zmiany w C API", "Changes in Version %(version)s — %(docstitle)s": "Zmiany w wersji %(version)s — %(docstitle)s", "Collapse sidebar": "Zwi\u0144 pasek boczny", "Complete Table of Contents": "Kompletny spis tre\u015bci", "Contents": "Tre\u015b\u0107", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Utworzone przy pomocy <a href=\"http://sphinx-doc.org/\">Sphinx</a>'a %(sphinx_version)s.", "Expand sidebar": "Rozwi\u0144 pasek boczny", "Full index on one page": "Ca\u0142y indeks na jednej stronie", "General Index": "Indeks og\u00f3lny", "Global Module Index": "Globalny indeks modu\u0142\u00f3w", "Go": "Szukaj", "Hide Search Matches": "Ukryj wyniki wyszukiwania", "Index": "Indeks", "Index – %(key)s": "Indeks – %(key)s", "Index pages by letter": "Strony indeksu alfabetycznie", "Indices and tables:": "Indeksy i tablice:", "Last updated on %(last_updated)s.": "Ostatnia modyfikacja %(last_updated)s.", "Library changes": "Zmiany w bibliotekach", "Navigation": "Nawigacja", "Next topic": "Nast\u0119pny temat", "Other changes": "Inne zmiany", "Overview": "Przegl\u0105d", "Permalink to this definition": "Sta\u0142y odno\u015bnik do tej definicji", "Permalink to this headline": "Sta\u0142y odno\u015bnik do tego nag\u0142\u00f3wka", "Please activate JavaScript to enable the search\n functionality.": "Aby umo\u017cliwi\u0107 wyszukiwanie, prosz\u0119 w\u0142\u0105czy\u0107 JavaScript.", "Preparing search...": "Inicjalizacja wyszukiwania...", "Previous topic": "Poprzedni temat", "Quick search": "Szybkie wyszukiwanie", "Search": "Szukaj", "Search Page": "Wyszukiwanie", "Search Results": "Wyniki wyszukiwania", "Search finished, found %s page(s) matching the search query.": "Wyszukiwanie zako\u0144czone. Liczba znalezionych stron pasuj\u0105cych do zapytania: %s.", "Search within %(docstitle)s": "Szukaj po\u015br\u00f3d %(docstitle)s", "Searching": "Wyszukiwanie", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Poka\u017c \u017ar\u00f3d\u0142o", "Table of Contents": "Spis tre\u015bci", "This Page": "Ta strona", "Welcome! This is": "Witaj! To jest", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Twoje wyszukiwanie nie da\u0142o \u017cadnych wynik\u00f3w. Upewnij si\u0119, \u017ce wszystkie s\u0142owa s\u0105 wpisane prawid\u0142owo i \u017ce wybra\u0142e\u015b dostateczn\u0105 ilo\u015b\u0107 kategorii.", "all functions, classes, terms": "wszystkie funkcje, klasy, terminy", "can be huge": "mo\u017ce by\u0107 ogromny", "last updated": "ostatnio aktualizowana", "lists all sections and subsections": "wszystkie rozdzia\u0142y i podrozdzia\u0142y", "next chapter": "nast\u0119pny rozdzia\u0142", "previous chapter": "poprzedni rozdzia\u0142", "quick access to all modules": "szybki dost\u0119p do wszystkich modu\u0142\u00f3w", "search": "szukaj", "search this documentation": "przeszukaj t\u0119 dokumentacj\u0119", "the documentation for": "dokumentacja do"}, "plural_expr": "(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "pl", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", w ", + "About these documents": "O tych dokumentach", + "Automatically generated list of changes in version %(version)s": "Automatycznie wygenerowana lista zmian w wersji %(version)s", + "C API changes": "Zmiany w C API", + "Changes in Version %(version)s — %(docstitle)s": "Zmiany w wersji %(version)s — %(docstitle)s", + "Collapse sidebar": "Zwi\u0144 pasek boczny", + "Complete Table of Contents": "Kompletny spis tre\u015bci", + "Contents": "Tre\u015b\u0107", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Utworzone przy pomocy <a href=\"http://sphinx-doc.org/\">Sphinx</a>'a %(sphinx_version)s.", + "Expand sidebar": "Rozwi\u0144 pasek boczny", + "Full index on one page": "Ca\u0142y indeks na jednej stronie", + "General Index": "Indeks og\u00f3lny", + "Global Module Index": "Globalny indeks modu\u0142\u00f3w", + "Go": "Szukaj", + "Hide Search Matches": "Ukryj wyniki wyszukiwania", + "Index": "Indeks", + "Index – %(key)s": "Indeks – %(key)s", + "Index pages by letter": "Strony indeksu alfabetycznie", + "Indices and tables:": "Indeksy i tablice:", + "Last updated on %(last_updated)s.": "Ostatnia modyfikacja %(last_updated)s.", + "Library changes": "Zmiany w bibliotekach", + "Navigation": "Nawigacja", + "Next topic": "Nast\u0119pny temat", + "Other changes": "Inne zmiany", + "Overview": "Przegl\u0105d", + "Permalink to this definition": "Sta\u0142y odno\u015bnik do tej definicji", + "Permalink to this headline": "Sta\u0142y odno\u015bnik do tego nag\u0142\u00f3wka", + "Please activate JavaScript to enable the search\n functionality.": "Aby umo\u017cliwi\u0107 wyszukiwanie, prosz\u0119 w\u0142\u0105czy\u0107 JavaScript.", + "Preparing search...": "Inicjalizacja wyszukiwania...", + "Previous topic": "Poprzedni temat", + "Quick search": "Szybkie wyszukiwanie", + "Search": "Szukaj", + "Search Page": "Wyszukiwanie", + "Search Results": "Wyniki wyszukiwania", + "Search finished, found %s page(s) matching the search query.": "Wyszukiwanie zako\u0144czone. Liczba znalezionych stron pasuj\u0105cych do zapytania: %s.", + "Search within %(docstitle)s": "Szukaj po\u015br\u00f3d %(docstitle)s", + "Searching": "Wyszukiwanie", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Poka\u017c \u017ar\u00f3d\u0142o", + "Table of Contents": "Spis tre\u015bci", + "This Page": "Ta strona", + "Welcome! This is": "Witaj! To jest", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Twoje wyszukiwanie nie da\u0142o \u017cadnych wynik\u00f3w. Upewnij si\u0119, \u017ce wszystkie s\u0142owa s\u0105 wpisane prawid\u0142owo i \u017ce wybra\u0142e\u015b dostateczn\u0105 ilo\u015b\u0107 kategorii.", + "all functions, classes, terms": "wszystkie funkcje, klasy, terminy", + "can be huge": "mo\u017ce by\u0107 ogromny", + "last updated": "ostatnio aktualizowana", + "lists all sections and subsections": "wszystkie rozdzia\u0142y i podrozdzia\u0142y", + "next chapter": "nast\u0119pny rozdzia\u0142", + "previous chapter": "poprzedni rozdzia\u0142", + "quick access to all modules": "szybki dost\u0119p do wszystkich modu\u0142\u00f3w", + "search": "szukaj", + "search this documentation": "przeszukaj t\u0119 dokumentacj\u0119", + "the documentation for": "dokumentacja do" + }, + "plural_expr": "(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3)" +});
\ No newline at end of file diff --git a/sphinx/locale/pl/LC_MESSAGES/sphinx.po b/sphinx/locale/pl/LC_MESSAGES/sphinx.po index ac8488a45..73b7a6478 100644 --- a/sphinx/locale/pl/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pl/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # m_aciek <maciej.olko@gmail.com>, 2017-2020 # Michael Gielda <michal.gielda@gmail.com>, 2014 diff --git a/sphinx/locale/pt/LC_MESSAGES/sphinx.js b/sphinx/locale/pt/LC_MESSAGES/sphinx.js index a70f17036..438b0b29a 100644 --- a/sphinx/locale/pt/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/pt/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "pt", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "pt", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/pt/LC_MESSAGES/sphinx.po b/sphinx/locale/pt/LC_MESSAGES/sphinx.po index 4b0c30cb7..e08ce7a5d 100644 --- a/sphinx/locale/pt/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pt/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js index f9bf19316..05516764d 100644 --- a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "pt_BR", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", em ", "About these documents": "Sobre esses documentos", "Automatically generated list of changes in version %(version)s": "Lista de altera\u00e7\u00f5es na vers\u00e3o %(version)s, gerada automaticamente", "C API changes": "Altera\u00e7\u00f5es na API C", "Changes in Version %(version)s — %(docstitle)s": "Modifica\u00e7\u00f5es na vers\u00e3o %(version)s — %(docstitle)s", "Collapse sidebar": "Recolher painel lateral", "Complete Table of Contents": "Tabela Completa dos Conte\u00fados", "Contents": "Conte\u00fados", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Criado usando <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Expandir painel lateral", "Full index on one page": "\u00cdndice completo em p\u00e1gina \u00fanica", "General Index": "\u00cdndice Geral", "Global Module Index": "\u00cdndice Global de M\u00f3dulos", "Go": "Ir", "Hide Search Matches": "Esconder Resultados da Busca", "Index": "\u00cdndice", "Index – %(key)s": "\u00cdndice – %(key)s", "Index pages by letter": "P\u00e1ginas de \u00edndice por letra", "Indices and tables:": "\u00cdndices e Tabelas:", "Last updated on %(last_updated)s.": "\u00daltima atualiza\u00e7\u00e3o em %(last_updated)s.", "Library changes": "Altera\u00e7\u00f5es na biblioteca", "Navigation": "Navega\u00e7\u00e3o", "Next topic": "Pr\u00f3ximo t\u00f3pico", "Other changes": "Outras altera\u00e7\u00f5es", "Overview": "Vis\u00e3o geral", "Permalink to this definition": "Link permanente para esta defini\u00e7\u00e3o", "Permalink to this headline": "Link permanente para este t\u00edtulo", "Please activate JavaScript to enable the search\n functionality.": "Por favor, ativar JavaScript para habilitar a\nfuncionalidade de busca.", "Preparing search...": "Preparando a busca...", "Previous topic": "T\u00f3pico anterior", "Quick search": "Busca r\u00e1pida", "Search": "Buscar", "Search Page": "P\u00e1gina de Busca", "Search Results": "Resultados da Busca", "Search finished, found %s page(s) matching the search query.": "Busca conclu\u00edda. %s p\u00e1gina(s) que atendem a consulta.", "Search within %(docstitle)s": "Pesquisar dentro de %(docstitle)s", "Searching": "Buscando", "Searching for multiple words only shows matches that contain\n all words.": "Pesquisando por v\u00e1rias palavras s\u00f3 mostra correspond\u00eancias\nque cont\u00eam todas as palavras.", "Show Source": "Exibir Fonte", "Table of Contents": "Tabela de Conte\u00fado", "This Page": "Essa P\u00e1gina", "Welcome! This is": "Bem Vindo! \u00c9 isso a\u00ed.", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Sua busca n\u00e3o encontrou nenhum documento. Por favor, confirme se todas as palavras est\u00e3o grafadas corretamente e se voc\u00ea selecionou categorias suficientes.", "all functions, classes, terms": "todas fun\u00e7\u00f5es, classes, termos", "can be huge": "pode ser enorme", "last updated": "\u00faltima atualiza\u00e7\u00e3o", "lists all sections and subsections": "Listar todas se\u00e7\u00f5es e subse\u00e7\u00f5es", "next chapter": "pr\u00f3ximo cap\u00edtulo", "previous chapter": "cap\u00edtulo anterior", "quick access to all modules": "acesso r\u00e1pido para todos os m\u00f3dulos", "search": "buscar", "search this documentation": "Buscar nessa documenta\u00e7\u00e3o", "the documentation for": "documenta\u00e7\u00e3o para"}, "plural_expr": "(n > 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "pt_BR", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", em ", + "About these documents": "Sobre esses documentos", + "Automatically generated list of changes in version %(version)s": "Lista de altera\u00e7\u00f5es na vers\u00e3o %(version)s, gerada automaticamente", + "C API changes": "Altera\u00e7\u00f5es na API C", + "Changes in Version %(version)s — %(docstitle)s": "Modifica\u00e7\u00f5es na vers\u00e3o %(version)s — %(docstitle)s", + "Collapse sidebar": "Recolher painel lateral", + "Complete Table of Contents": "Tabela Completa dos Conte\u00fados", + "Contents": "Conte\u00fados", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Criado usando <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Expandir painel lateral", + "Full index on one page": "\u00cdndice completo em p\u00e1gina \u00fanica", + "General Index": "\u00cdndice Geral", + "Global Module Index": "\u00cdndice Global de M\u00f3dulos", + "Go": "Ir", + "Hide Search Matches": "Esconder Resultados da Busca", + "Index": "\u00cdndice", + "Index – %(key)s": "\u00cdndice – %(key)s", + "Index pages by letter": "P\u00e1ginas de \u00edndice por letra", + "Indices and tables:": "\u00cdndices e Tabelas:", + "Last updated on %(last_updated)s.": "\u00daltima atualiza\u00e7\u00e3o em %(last_updated)s.", + "Library changes": "Altera\u00e7\u00f5es na biblioteca", + "Navigation": "Navega\u00e7\u00e3o", + "Next topic": "Pr\u00f3ximo t\u00f3pico", + "Other changes": "Outras altera\u00e7\u00f5es", + "Overview": "Vis\u00e3o geral", + "Permalink to this definition": "Link permanente para esta defini\u00e7\u00e3o", + "Permalink to this headline": "Link permanente para este t\u00edtulo", + "Please activate JavaScript to enable the search\n functionality.": "Por favor, ativar JavaScript para habilitar a\nfuncionalidade de busca.", + "Preparing search...": "Preparando a busca...", + "Previous topic": "T\u00f3pico anterior", + "Quick search": "Busca r\u00e1pida", + "Search": "Buscar", + "Search Page": "P\u00e1gina de Busca", + "Search Results": "Resultados da Busca", + "Search finished, found %s page(s) matching the search query.": "Busca conclu\u00edda. %s p\u00e1gina(s) que atendem a consulta.", + "Search within %(docstitle)s": "Pesquisar dentro de %(docstitle)s", + "Searching": "Buscando", + "Searching for multiple words only shows matches that contain\n all words.": "Pesquisando por v\u00e1rias palavras s\u00f3 mostra correspond\u00eancias\nque cont\u00eam todas as palavras.", + "Show Source": "Exibir Fonte", + "Table of Contents": "Tabela de Conte\u00fado", + "This Page": "Essa P\u00e1gina", + "Welcome! This is": "Bem Vindo! \u00c9 isso a\u00ed.", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Sua busca n\u00e3o encontrou nenhum documento. Por favor, confirme se todas as palavras est\u00e3o grafadas corretamente e se voc\u00ea selecionou categorias suficientes.", + "all functions, classes, terms": "todas fun\u00e7\u00f5es, classes, termos", + "can be huge": "pode ser enorme", + "last updated": "\u00faltima atualiza\u00e7\u00e3o", + "lists all sections and subsections": "Listar todas se\u00e7\u00f5es e subse\u00e7\u00f5es", + "next chapter": "pr\u00f3ximo cap\u00edtulo", + "previous chapter": "cap\u00edtulo anterior", + "quick access to all modules": "acesso r\u00e1pido para todos os m\u00f3dulos", + "search": "buscar", + "search this documentation": "Buscar nessa documenta\u00e7\u00e3o", + "the documentation for": "documenta\u00e7\u00e3o para" + }, + "plural_expr": "(n > 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po index dba58f93e..3e9e2965f 100644 --- a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Claudio Rogerio Carvalho Filho <excriptbrasil@gmail.com>, 2016 # FIRST AUTHOR <roger.demetrescu@gmail.com>, 2008 diff --git a/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.js b/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.js index 243fbda4c..88739083b 100644 --- a/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "pt_PT", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": ", em", "About these documents": "Sobre estes documentos", "Automatically generated list of changes in version %(version)s": "Lista de altera\u00e7\u00f5es gerada automaticamente na vers\u00e3o %(version)s", "C API changes": "Altera\u00e7\u00f5es na API C", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Recolher painel lateral", "Complete Table of Contents": "Tabela de Conte\u00fados Completa", "Contents": "Conte\u00fado", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Criado utilizando <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Expandir painel lateral", "Full index on one page": "\u00cdndice completo numa p\u00e1gina", "General Index": "\u00cdndice Geral", "Global Module Index": "\u00cdndice Global de M\u00f3dulos", "Go": "Ir", "Hide Search Matches": "Esconder Resultados da Pesquisa", "Index": "\u00cdndice", "Index – %(key)s": "\u00cdndice – %(key)s", "Index pages by letter": "Paginas de \u00edndice por letra", "Indices and tables:": "\u00cdndices e tabelas:", "Last updated on %(last_updated)s.": "\u00daltima actualiza\u00e7\u00e3o em %(last_updated)s.", "Library changes": "Altera\u00e7\u00f5es na biblioteca", "Navigation": "Navega\u00e7\u00e3o", "Next topic": "Pr\u00f3ximo t\u00f3pico", "Other changes": "Outras altera\u00e7\u00f5es", "Overview": "Vis\u00e3o geral", "Permalink to this definition": "Link permanente para esta defini\u00e7\u00e3o", "Permalink to this headline": "Link permanente para este t\u00edtulo", "Please activate JavaScript to enable the search\n functionality.": "Por favor ligue o JavaScript para habilitar a\nfuncionalidade de pesquisa.", "Preparing search...": "A preparar a pesquisa...", "Previous topic": "T\u00f3pico anterior", "Quick search": "Pesquisa r\u00e1pida", "Search": "Pesquisar", "Search Page": "P\u00e1gina de Pesquisa", "Search Results": "Resultados da Pesquisa", "Search finished, found %s page(s) matching the search query.": "Pesquisa conclu\u00edda, foram encontrada(s) %s p\u00e1gina(s) que combinam com a consulta feita.", "Search within %(docstitle)s": "Pesquisar dentro de %(docstitle)s", "Searching": "A Pesquisar", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Exibir Fonte", "Table of Contents": "", "This Page": "Esta P\u00e1gina", "Welcome! This is": "Bem Vindo(a)! Esta \u00e9", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "A sua pesquisa n\u00e3o encontrou nenhum documento. Por favor, confirme que todas as palavras est\u00e3o escritas corretamente e que selecionou categorias suficientes.", "all functions, classes, terms": "todas as fun\u00e7\u00f5es, classes, termos", "can be huge": "pode ser enorme", "last updated": "\u00faltima actualiza\u00e7\u00e3o", "lists all sections and subsections": "Listar todas as sec\u00e7\u00f5es e subsec\u00e7\u00f5es", "next chapter": "pr\u00f3ximo cap\u00edtulo", "previous chapter": "cap\u00edtulo anterior", "quick access to all modules": "acesso r\u00e1pido a todos os m\u00f3dulos", "search": "pesquisar", "search this documentation": "Pesquisar esta documenta\u00e7\u00e3o", "the documentation for": "a documenta\u00e7\u00e3o de"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "pt_PT", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": ", em", + "About these documents": "Sobre estes documentos", + "Automatically generated list of changes in version %(version)s": "Lista de altera\u00e7\u00f5es gerada automaticamente na vers\u00e3o %(version)s", + "C API changes": "Altera\u00e7\u00f5es na API C", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Recolher painel lateral", + "Complete Table of Contents": "Tabela de Conte\u00fados Completa", + "Contents": "Conte\u00fado", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Criado utilizando <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Expandir painel lateral", + "Full index on one page": "\u00cdndice completo numa p\u00e1gina", + "General Index": "\u00cdndice Geral", + "Global Module Index": "\u00cdndice Global de M\u00f3dulos", + "Go": "Ir", + "Hide Search Matches": "Esconder Resultados da Pesquisa", + "Index": "\u00cdndice", + "Index – %(key)s": "\u00cdndice – %(key)s", + "Index pages by letter": "Paginas de \u00edndice por letra", + "Indices and tables:": "\u00cdndices e tabelas:", + "Last updated on %(last_updated)s.": "\u00daltima actualiza\u00e7\u00e3o em %(last_updated)s.", + "Library changes": "Altera\u00e7\u00f5es na biblioteca", + "Navigation": "Navega\u00e7\u00e3o", + "Next topic": "Pr\u00f3ximo t\u00f3pico", + "Other changes": "Outras altera\u00e7\u00f5es", + "Overview": "Vis\u00e3o geral", + "Permalink to this definition": "Link permanente para esta defini\u00e7\u00e3o", + "Permalink to this headline": "Link permanente para este t\u00edtulo", + "Please activate JavaScript to enable the search\n functionality.": "Por favor ligue o JavaScript para habilitar a\nfuncionalidade de pesquisa.", + "Preparing search...": "A preparar a pesquisa...", + "Previous topic": "T\u00f3pico anterior", + "Quick search": "Pesquisa r\u00e1pida", + "Search": "Pesquisar", + "Search Page": "P\u00e1gina de Pesquisa", + "Search Results": "Resultados da Pesquisa", + "Search finished, found %s page(s) matching the search query.": "Pesquisa conclu\u00edda, foram encontrada(s) %s p\u00e1gina(s) que combinam com a consulta feita.", + "Search within %(docstitle)s": "Pesquisar dentro de %(docstitle)s", + "Searching": "A Pesquisar", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Exibir Fonte", + "Table of Contents": "", + "This Page": "Esta P\u00e1gina", + "Welcome! This is": "Bem Vindo(a)! Esta \u00e9", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "A sua pesquisa n\u00e3o encontrou nenhum documento. Por favor, confirme que todas as palavras est\u00e3o escritas corretamente e que selecionou categorias suficientes.", + "all functions, classes, terms": "todas as fun\u00e7\u00f5es, classes, termos", + "can be huge": "pode ser enorme", + "last updated": "\u00faltima actualiza\u00e7\u00e3o", + "lists all sections and subsections": "Listar todas as sec\u00e7\u00f5es e subsec\u00e7\u00f5es", + "next chapter": "pr\u00f3ximo cap\u00edtulo", + "previous chapter": "cap\u00edtulo anterior", + "quick access to all modules": "acesso r\u00e1pido a todos os m\u00f3dulos", + "search": "pesquisar", + "search this documentation": "Pesquisar esta documenta\u00e7\u00e3o", + "the documentation for": "a documenta\u00e7\u00e3o de" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po b/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po index 7d219561a..6c78b0813 100644 --- a/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Pedro Algarvio <pedro@algarvio.me>, 2013 # Takeshi KOMIYA <i.tkomiya@gmail.com>, 2016 diff --git a/sphinx/locale/ro/LC_MESSAGES/sphinx.js b/sphinx/locale/ro/LC_MESSAGES/sphinx.js index f93f990af..8ba5236b7 100644 --- a/sphinx/locale/ro/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ro/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ro", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": ", \u00een", "About these documents": "Despre aceste documente", "Automatically generated list of changes in version %(version)s": "Lista de schimb\u0103ri generat\u0103 automat pentru versiunea %(version)s", "C API changes": "Schimb\u0103ri \u00een API C", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Ascundere bar\u0103 lateral\u0103", "Complete Table of Contents": "Cuprinsul Complet", "Contents": "Cuprins", "Copyright": "Drepturi de autor", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Generat cu <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Expandare bar\u0103 lateral\u0103", "Full index on one page": "Index complet", "General Index": "Index General", "Global Module Index": "Index Module Globale", "Go": "Caut\u0103", "Hide Search Matches": "Ascunde Rezultatele C\u0103ut\u0103rii", "Index": "Index", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "Indexeaz\u0103 paginile dupa liter\u0103", "Indices and tables:": "Indici \u0219i tabele:", "Last updated on %(last_updated)s.": "Ultima actualizare la %(last_updated)s.", "Library changes": "Schimb\u0103ri \u00een bibliotec\u0103", "Navigation": "Navigare", "Next topic": "Subiectul urm\u0103tor", "Other changes": "Alte schimb\u0103ri", "Overview": "Prezentare general\u0103", "Permalink to this definition": "Link permanent la aceast\u0103 defini\u021bie", "Permalink to this headline": "Link permanent la acest titlu", "Please activate JavaScript to enable the search\n functionality.": "Activeaz\u0103 JavaScript pentru a permite\nfunc\u021bia de c\u0103utare.", "Preparing search...": "Se preg\u0103te\u0219te c\u0103utarea...", "Previous topic": "Subiectul precedent", "Quick search": "C\u0103utare rapid\u0103", "Search": "C\u0103utare", "Search Page": "Pagin\u0103 de C\u0103utare", "Search Results": "Rezultatele C\u0103ut\u0103rii", "Search finished, found %s page(s) matching the search query.": "C\u0103utare finalizat\u0103, au fost g\u0103site %s pagini care au corespuns c\u0103ut\u0103rii.", "Search within %(docstitle)s": "Caut\u0103 \u00een %(docstitle)s", "Searching": "C\u0103utare", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Vezi Sursa", "Table of Contents": "", "This Page": "Aceast\u0103 Pagin\u0103", "Welcome! This is": "Bine ai venit! Acesta este", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "C\u0103utarea nu a identificat nici un document. Te rog s\u0103 te asiguri c\u0103 toate cuvintele sunt scrise corect \u0219i c\u0103 ai selectat suficiente categorii.", "all functions, classes, terms": "toate func\u021biile, clasele, termenii", "can be huge": "poate fi extrem de mare", "last updated": "ultima actualizare", "lists all sections and subsections": "lista tuturor sec\u021biunilor si a subsec\u021biunilor", "next chapter": "capitolul urm\u0103tor", "previous chapter": "capitolul precedent", "quick access to all modules": "acces rapid la toate modulele", "search": "c\u0103utare", "search this documentation": "caut\u0103 \u00een aceast\u0103 documenta\u021bie", "the documentation for": "documenta\u021bia pentru"}, "plural_expr": "(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1))"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ro", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": ", \u00een", + "About these documents": "Despre aceste documente", + "Automatically generated list of changes in version %(version)s": "Lista de schimb\u0103ri generat\u0103 automat pentru versiunea %(version)s", + "C API changes": "Schimb\u0103ri \u00een API C", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Ascundere bar\u0103 lateral\u0103", + "Complete Table of Contents": "Cuprinsul Complet", + "Contents": "Cuprins", + "Copyright": "Drepturi de autor", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Generat cu <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Expandare bar\u0103 lateral\u0103", + "Full index on one page": "Index complet", + "General Index": "Index General", + "Global Module Index": "Index Module Globale", + "Go": "Caut\u0103", + "Hide Search Matches": "Ascunde Rezultatele C\u0103ut\u0103rii", + "Index": "Index", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "Indexeaz\u0103 paginile dupa liter\u0103", + "Indices and tables:": "Indici \u0219i tabele:", + "Last updated on %(last_updated)s.": "Ultima actualizare la %(last_updated)s.", + "Library changes": "Schimb\u0103ri \u00een bibliotec\u0103", + "Navigation": "Navigare", + "Next topic": "Subiectul urm\u0103tor", + "Other changes": "Alte schimb\u0103ri", + "Overview": "Prezentare general\u0103", + "Permalink to this definition": "Link permanent la aceast\u0103 defini\u021bie", + "Permalink to this headline": "Link permanent la acest titlu", + "Please activate JavaScript to enable the search\n functionality.": "Activeaz\u0103 JavaScript pentru a permite\nfunc\u021bia de c\u0103utare.", + "Preparing search...": "Se preg\u0103te\u0219te c\u0103utarea...", + "Previous topic": "Subiectul precedent", + "Quick search": "C\u0103utare rapid\u0103", + "Search": "C\u0103utare", + "Search Page": "Pagin\u0103 de C\u0103utare", + "Search Results": "Rezultatele C\u0103ut\u0103rii", + "Search finished, found %s page(s) matching the search query.": "C\u0103utare finalizat\u0103, au fost g\u0103site %s pagini care au corespuns c\u0103ut\u0103rii.", + "Search within %(docstitle)s": "Caut\u0103 \u00een %(docstitle)s", + "Searching": "C\u0103utare", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Vezi Sursa", + "Table of Contents": "", + "This Page": "Aceast\u0103 Pagin\u0103", + "Welcome! This is": "Bine ai venit! Acesta este", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "C\u0103utarea nu a identificat nici un document. Te rog s\u0103 te asiguri c\u0103 toate cuvintele sunt scrise corect \u0219i c\u0103 ai selectat suficiente categorii.", + "all functions, classes, terms": "toate func\u021biile, clasele, termenii", + "can be huge": "poate fi extrem de mare", + "last updated": "ultima actualizare", + "lists all sections and subsections": "lista tuturor sec\u021biunilor si a subsec\u021biunilor", + "next chapter": "capitolul urm\u0103tor", + "previous chapter": "capitolul precedent", + "quick access to all modules": "acces rapid la toate modulele", + "search": "c\u0103utare", + "search this documentation": "caut\u0103 \u00een aceast\u0103 documenta\u021bie", + "the documentation for": "documenta\u021bia pentru" + }, + "plural_expr": "(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1))" +});
\ No newline at end of file diff --git a/sphinx/locale/ro/LC_MESSAGES/sphinx.po b/sphinx/locale/ro/LC_MESSAGES/sphinx.po index 6a4591643..721f8dcd2 100644 --- a/sphinx/locale/ro/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ro/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Razvan Stefanescu <razvan.stefanescu@gmail.com>, 2015-2017 # Takeshi KOMIYA <i.tkomiya@gmail.com>, 2016 diff --git a/sphinx/locale/ru/LC_MESSAGES/sphinx.js b/sphinx/locale/ru/LC_MESSAGES/sphinx.js index eae78b3a8..2573063da 100644 --- a/sphinx/locale/ru/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ru/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ru", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", \u0432", "About these documents": "\u041e\u0431 \u044d\u0442\u0438\u0445 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0445", "Automatically generated list of changes in version %(version)s": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0440\u0441\u0438\u0438 %(version)s", "C API changes": "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 API C", "Changes in Version %(version)s — %(docstitle)s": "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0432\u0435\u0440\u0441\u0438\u0438 %(version)s — %(docstitle)s", "Collapse sidebar": "\u0421\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0431\u043e\u043a\u043e\u0432\u0443\u044e \u043f\u0430\u043d\u0435\u043b\u044c", "Complete Table of Contents": "\u041f\u043e\u043b\u043d\u043e\u0435 \u043e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435", "Contents": "\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435", "Copyright": "\u0410\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u0435 \u043f\u0440\u0430\u0432\u0430", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u0421\u043e\u0437\u0434\u0430\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0431\u043e\u043a\u043e\u0432\u0443\u044e \u043f\u0430\u043d\u0435\u043b\u044c", "Full index on one page": "\u041f\u043e\u043b\u043d\u044b\u0439 \u0430\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435", "General Index": "\u0410\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c", "Global Module Index": "\u0410\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0434\u0443\u043b\u0435\u0439", "Go": "\u0418\u0441\u043a\u0430\u0442\u044c", "Hide Search Matches": "\u0421\u043d\u044f\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435", "Index": "\u0410\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c", "Index – %(key)s": "\u0410\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c – %(key)s", "Index pages by letter": "\u0423\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438 \u043f\u043e \u0431\u0443\u043a\u0432\u0430\u043c \u0430\u043b\u0444\u0430\u0432\u0438\u0442\u0430", "Indices and tables:": "\u0422\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438:", "Last updated on %(last_updated)s.": "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043e: %(last_updated)s.", "Library changes": "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435", "Navigation": "\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f", "Next topic": "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437\u0434\u0435\u043b", "Other changes": "\u0414\u0440\u0443\u0433\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f", "Overview": "\u041e\u0431\u0437\u043e\u0440", "Permalink to this definition": "\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u044d\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435", "Permalink to this headline": "\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a", "Please activate JavaScript to enable the search\n functionality.": "\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 JavaScript \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435.", "Preparing search...": "\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430\u2026", "Previous topic": "\u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0440\u0430\u0437\u0434\u0435\u043b", "Quick search": "\u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u043f\u043e\u0438\u0441\u043a", "Search": "\u041f\u043e\u0438\u0441\u043a", "Search Page": "\u041f\u043e\u0438\u0441\u043a", "Search Results": "\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430", "Search finished, found %s page(s) matching the search query.": "\u041f\u043e\u0438\u0441\u043a \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d, \u043d\u0430\u0439\u0434\u0435\u043d\u043e %s \u0441\u0442\u0440\u0430\u043d\u0438\u0446, \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0449\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0443.", "Search within %(docstitle)s": "\u041f\u043e\u0438\u0441\u043a \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435 \u00ab%(docstitle)s\u00bb", "Searching": "\u0418\u0434\u0451\u0442 \u043f\u043e\u0438\u0441\u043a", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442", "Table of Contents": "\u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435", "This Page": "\u042d\u0442\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430", "Welcome! This is": "\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c! \u042d\u0442\u043e", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u041f\u043e \u0432\u0430\u0448\u0435\u043c\u0443 \u043f\u043e\u0438\u0441\u043a\u0443 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435, \u0447\u0442\u043e \u0432\u0441\u0435 \u0441\u043b\u043e\u0432\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a, \u0438 \u0447\u0442\u043e \u0432\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439.", "all functions, classes, terms": "\u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043b\u0430\u0441\u0441\u044b, \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b", "can be huge": "\u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0431\u043e\u043b\u044c\u0448\u0438\u043c", "last updated": "\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435", "lists all sections and subsections": "\u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432 \u0438 \u043f\u043e\u0434\u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432", "next chapter": "\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0433\u043b\u0430\u0432\u0430", "previous chapter": "\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u0433\u043b\u0430\u0432\u0430", "quick access to all modules": "\u0441\u0432\u043e\u0434\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439", "search": "\u0438\u0441\u043a\u0430\u0442\u044c", "search this documentation": "\u043f\u043e\u0438\u0441\u043a \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438", "the documentation for": "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f"}, "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ru", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", \u0432", + "About these documents": "\u041e\u0431 \u044d\u0442\u0438\u0445 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0445", + "Automatically generated list of changes in version %(version)s": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0432\u0435\u0440\u0441\u0438\u0438 %(version)s", + "C API changes": "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 API C", + "Changes in Version %(version)s — %(docstitle)s": "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0432\u0435\u0440\u0441\u0438\u0438 %(version)s — %(docstitle)s", + "Collapse sidebar": "\u0421\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0431\u043e\u043a\u043e\u0432\u0443\u044e \u043f\u0430\u043d\u0435\u043b\u044c", + "Complete Table of Contents": "\u041f\u043e\u043b\u043d\u043e\u0435 \u043e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435", + "Contents": "\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435", + "Copyright": "\u0410\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u0435 \u043f\u0440\u0430\u0432\u0430", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u0421\u043e\u0437\u0434\u0430\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0431\u043e\u043a\u043e\u0432\u0443\u044e \u043f\u0430\u043d\u0435\u043b\u044c", + "Full index on one page": "\u041f\u043e\u043b\u043d\u044b\u0439 \u0430\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435", + "General Index": "\u0410\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c", + "Global Module Index": "\u0410\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0434\u0443\u043b\u0435\u0439", + "Go": "\u0418\u0441\u043a\u0430\u0442\u044c", + "Hide Search Matches": "\u0421\u043d\u044f\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435", + "Index": "\u0410\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c", + "Index – %(key)s": "\u0410\u043b\u0444\u0430\u0432\u0438\u0442\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c – %(key)s", + "Index pages by letter": "\u0423\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438 \u043f\u043e \u0431\u0443\u043a\u0432\u0430\u043c \u0430\u043b\u0444\u0430\u0432\u0438\u0442\u0430", + "Indices and tables:": "\u0422\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438:", + "Last updated on %(last_updated)s.": "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043e: %(last_updated)s.", + "Library changes": "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435", + "Navigation": "\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f", + "Next topic": "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437\u0434\u0435\u043b", + "Other changes": "\u0414\u0440\u0443\u0433\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f", + "Overview": "\u041e\u0431\u0437\u043e\u0440", + "Permalink to this definition": "\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u044d\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435", + "Permalink to this headline": "\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a", + "Please activate JavaScript to enable the search\n functionality.": "\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 JavaScript \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435.", + "Preparing search...": "\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430\u2026", + "Previous topic": "\u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0440\u0430\u0437\u0434\u0435\u043b", + "Quick search": "\u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u043f\u043e\u0438\u0441\u043a", + "Search": "\u041f\u043e\u0438\u0441\u043a", + "Search Page": "\u041f\u043e\u0438\u0441\u043a", + "Search Results": "\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430", + "Search finished, found %s page(s) matching the search query.": "\u041f\u043e\u0438\u0441\u043a \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d, \u043d\u0430\u0439\u0434\u0435\u043d\u043e %s \u0441\u0442\u0440\u0430\u043d\u0438\u0446, \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0449\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0443.", + "Search within %(docstitle)s": "\u041f\u043e\u0438\u0441\u043a \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435 \u00ab%(docstitle)s\u00bb", + "Searching": "\u0418\u0434\u0451\u0442 \u043f\u043e\u0438\u0441\u043a", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442", + "Table of Contents": "\u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435", + "This Page": "\u042d\u0442\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430", + "Welcome! This is": "\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c! \u042d\u0442\u043e", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u041f\u043e \u0432\u0430\u0448\u0435\u043c\u0443 \u043f\u043e\u0438\u0441\u043a\u0443 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435, \u0447\u0442\u043e \u0432\u0441\u0435 \u0441\u043b\u043e\u0432\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a, \u0438 \u0447\u0442\u043e \u0432\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439.", + "all functions, classes, terms": "\u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043b\u0430\u0441\u0441\u044b, \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b", + "can be huge": "\u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0431\u043e\u043b\u044c\u0448\u0438\u043c", + "last updated": "\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435", + "lists all sections and subsections": "\u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432 \u0438 \u043f\u043e\u0434\u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432", + "next chapter": "\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0433\u043b\u0430\u0432\u0430", + "previous chapter": "\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u0433\u043b\u0430\u0432\u0430", + "quick access to all modules": "\u0441\u0432\u043e\u0434\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439", + "search": "\u0438\u0441\u043a\u0430\u0442\u044c", + "search this documentation": "\u043f\u043e\u0438\u0441\u043a \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438", + "the documentation for": "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f" + }, + "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3)" +});
\ No newline at end of file diff --git a/sphinx/locale/ru/LC_MESSAGES/sphinx.po b/sphinx/locale/ru/LC_MESSAGES/sphinx.po index e69207f4e..d8572db5f 100644 --- a/sphinx/locale/ru/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ru/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Alex Salikov <Salikvo57@gmail.com>, 2019 # Dmitry Shachnev <mitya57@gmail.com>, 2013 diff --git a/sphinx/locale/si/LC_MESSAGES/sphinx.js b/sphinx/locale/si/LC_MESSAGES/sphinx.js index 753b43b5f..d324d9a36 100644 --- a/sphinx/locale/si/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/si/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "si", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "\u0db8\u0dd9\u0db8 \u0dbd\u0dda\u0d9b\u0dab \u0d9c\u0dd0\u0db1", "Automatically generated list of changes in version %(version)s": "", "C API changes": "C API \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0db8\u0dca", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "\u0dc3\u0db8\u0dca\u0db4\u0dd6\u0dbb\u0dca\u0dab \u0db4\u0da7\u0dd4\u0db1", "Contents": "\u0d85\u0db1\u0dca\u0dad\u0dbb\u0dca\u0d9c\u0dad\u0dba", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "\u0dba\u0db1\u0dca\u0db1", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "\u0db4\u0dd4\u0dc3\u0dca\u0dad\u0d9a\u0dcf\u0dbd \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0db8\u0dca", "Navigation": "\u0d9c\u0db8\u0db1\u0dca \u0d9a\u0dd2\u0dbb\u0dd3\u0db8", "Next topic": "\u0d8a\u0dc5\u0d9f \u0db8\u0dcf\u0dad\u0dd8\u0d9a\u0dcf\u0dc0", "Other changes": "\u0dc0\u0dd9\u0db1\u0dad\u0dca \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0db8\u0dca", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "\u0dc3\u0dd9\u0dc0\u0dd4\u0db8 \u0dc3\u0dd6\u0daf\u0dcf\u0db1\u0db8\u0dca \u0d9a\u0dbb\u0db8\u0dd2\u0db1\u0dca....", "Previous topic": "\u0db4\u0dd9\u0dbb \u0db8\u0dcf\u0dad\u0dd8\u0d9a\u0dcf\u0dc0", "Quick search": "\u0d89\u0d9a\u0dca\u0db8\u0db1\u0dca \u0dc3\u0dd9\u0dc0\u0dd4\u0db8", "Search": "\u0dc3\u0ddc\u0dba\u0db1\u0dca\u0db1", "Search Page": "\u0dc3\u0dd9\u0dc0\u0dd4\u0db8\u0dca \u0db4\u0dd2\u0da7\u0dd4\u0dc0", "Search Results": "\u0dc3\u0dd9\u0dc0\u0dd4\u0db8\u0dca \u0db4\u0dca\u200d\u0dbb\u0dad\u0dd2\u0db5\u0dbd", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "\u0dc3\u0ddc\u0dba\u0db8\u0dd2\u0db1\u0dca...", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u0db8\u0dd6\u0dbd\u0dba \u0db4\u0dd9\u0db1\u0dca\u0dc0\u0db1\u0dca\u0db1", "Table of Contents": "", "This Page": "\u0db8\u0dd9\u0db8 \u0db4\u0dd2\u0da7\u0dd4\u0dc0", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "\u0dc0\u0dd2\u0dc1\u0dcf\u0dbd \u0dc0\u0dd2\u0dba \u0dc4\u0dd0\u0d9a", "last updated": "\u0d85\u0dc0\u0dc3\u0db1\u0dca\u0dc0\u0dbb\u0da7 \u0dba\u0dcf\u0dc0\u0dad\u0dca\u0d9a\u0dcf\u0dbd \u0d9a\u0dbd", "lists all sections and subsections": "", "next chapter": "\u0d8a\u0dc5\u0d9f \u0db4\u0dbb\u0dd2\u0da0\u0dca\u0da1\u0dda\u0daf\u0dba", "previous chapter": "\u0db4\u0dd9\u0dbb \u0db4\u0dbb\u0dd2\u0da0\u0dca\u0da1\u0dda\u0daf\u0dba", "quick access to all modules": "", "search": "\u0dc3\u0ddc\u0dba\u0db1\u0dca\u0db1", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "si", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "\u0db8\u0dd9\u0db8 \u0dbd\u0dda\u0d9b\u0dab \u0d9c\u0dd0\u0db1", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "C API \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0db8\u0dca", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "\u0dc3\u0db8\u0dca\u0db4\u0dd6\u0dbb\u0dca\u0dab \u0db4\u0da7\u0dd4\u0db1", + "Contents": "\u0d85\u0db1\u0dca\u0dad\u0dbb\u0dca\u0d9c\u0dad\u0dba", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "\u0dba\u0db1\u0dca\u0db1", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "\u0db4\u0dd4\u0dc3\u0dca\u0dad\u0d9a\u0dcf\u0dbd \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0db8\u0dca", + "Navigation": "\u0d9c\u0db8\u0db1\u0dca \u0d9a\u0dd2\u0dbb\u0dd3\u0db8", + "Next topic": "\u0d8a\u0dc5\u0d9f \u0db8\u0dcf\u0dad\u0dd8\u0d9a\u0dcf\u0dc0", + "Other changes": "\u0dc0\u0dd9\u0db1\u0dad\u0dca \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0db8\u0dca", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "\u0dc3\u0dd9\u0dc0\u0dd4\u0db8 \u0dc3\u0dd6\u0daf\u0dcf\u0db1\u0db8\u0dca \u0d9a\u0dbb\u0db8\u0dd2\u0db1\u0dca....", + "Previous topic": "\u0db4\u0dd9\u0dbb \u0db8\u0dcf\u0dad\u0dd8\u0d9a\u0dcf\u0dc0", + "Quick search": "\u0d89\u0d9a\u0dca\u0db8\u0db1\u0dca \u0dc3\u0dd9\u0dc0\u0dd4\u0db8", + "Search": "\u0dc3\u0ddc\u0dba\u0db1\u0dca\u0db1", + "Search Page": "\u0dc3\u0dd9\u0dc0\u0dd4\u0db8\u0dca \u0db4\u0dd2\u0da7\u0dd4\u0dc0", + "Search Results": "\u0dc3\u0dd9\u0dc0\u0dd4\u0db8\u0dca \u0db4\u0dca\u200d\u0dbb\u0dad\u0dd2\u0db5\u0dbd", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "\u0dc3\u0ddc\u0dba\u0db8\u0dd2\u0db1\u0dca...", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u0db8\u0dd6\u0dbd\u0dba \u0db4\u0dd9\u0db1\u0dca\u0dc0\u0db1\u0dca\u0db1", + "Table of Contents": "", + "This Page": "\u0db8\u0dd9\u0db8 \u0db4\u0dd2\u0da7\u0dd4\u0dc0", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "\u0dc0\u0dd2\u0dc1\u0dcf\u0dbd \u0dc0\u0dd2\u0dba \u0dc4\u0dd0\u0d9a", + "last updated": "\u0d85\u0dc0\u0dc3\u0db1\u0dca\u0dc0\u0dbb\u0da7 \u0dba\u0dcf\u0dc0\u0dad\u0dca\u0d9a\u0dcf\u0dbd \u0d9a\u0dbd", + "lists all sections and subsections": "", + "next chapter": "\u0d8a\u0dc5\u0d9f \u0db4\u0dbb\u0dd2\u0da0\u0dca\u0da1\u0dda\u0daf\u0dba", + "previous chapter": "\u0db4\u0dd9\u0dbb \u0db4\u0dbb\u0dd2\u0da0\u0dca\u0da1\u0dda\u0daf\u0dba", + "quick access to all modules": "", + "search": "\u0dc3\u0ddc\u0dba\u0db1\u0dca\u0db1", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/si/LC_MESSAGES/sphinx.po b/sphinx/locale/si/LC_MESSAGES/sphinx.po index a257711c5..d03be451e 100644 --- a/sphinx/locale/si/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/si/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # callkalpa <callkalpa@gmail.com>, 2013 msgid "" diff --git a/sphinx/locale/sk/LC_MESSAGES/sphinx.js b/sphinx/locale/sk/LC_MESSAGES/sphinx.js index f8e8e5e05..c76078293 100644 --- a/sphinx/locale/sk/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/sk/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "sk", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", ", in ": ", v ", "About these documents": "O dokument\u00e1cii", "Automatically generated list of changes in version %(version)s": "Automaticky generovan\u00fd zoznam zmien vo verzii %(version)s", "C API changes": "Zmeny API C", "Changes in Version %(version)s — %(docstitle)s": "Zmeny vo verzii %(version)s — %(docstitle)s", "Collapse sidebar": "Zbali\u0165 bo\u010dn\u00fd panel", "Complete Table of Contents": "Celkov\u00fd obsah", "Contents": "Obsah", "Copyright": "Autorsk\u00e9 pr\u00e1vo", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Vytvoren\u00e9 pomocou <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Rozbali\u0165 bo\u010dn\u00fd panel", "Full index on one page": "Cel\u00fd index na jednej strane", "General Index": "V\u0161eobecn\u00fd index", "Global Module Index": "Celkov\u00fd index modulov", "Go": "OK", "Hide Search Matches": "Skry\u0165 v\u00fdsledky h\u013eadania", "Index": "Index", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "Indexov\u00e9 str\u00e1nky po p\u00edsmen\u00e1ch", "Indices and tables:": "Indexy a tabu\u013eky", "Last updated on %(last_updated)s.": "Naposledy aktualizovan\u00e9 %(last_updated)s.", "Library changes": "Zmeny kni\u017enice", "Navigation": "Navig\u00e1cia", "Next topic": "\u010eal\u0161ia t\u00e9ma", "Other changes": "Ostatn\u00e9 zmeny", "Overview": "Preh\u013ead", "Permalink to this definition": "Trval\u00fd odkaz na t\u00fato defin\u00edciu", "Permalink to this headline": "Trval\u00fd odkaz na tento nadpis", "Please activate JavaScript to enable the search\n functionality.": "Pros\u00edm, na zapnutie funkcie h\u013eadania,aktivujte\nJavaScript .", "Preparing search...": "Pr\u00edprava h\u013eadania...", "Previous topic": "Predo\u0161l\u00e1 t\u00e9ma", "Quick search": "R\u00fdchle h\u013eadanie", "Search": "H\u013eada\u0165", "Search Page": "Str\u00e1nka h\u013eadania", "Search Results": "V\u00fdsledky h\u013eadania", "Search finished, found %s page(s) matching the search query.": "H\u013eadanie dokon\u010den\u00e9, n\u00e1jden\u00e9 %s strana(y), ktor\u00e9 vyhovuj\u00fa h\u013eadan\u00e9mu v\u00fdrazu.", "Search within %(docstitle)s": "H\u013eada\u0165 v %(docstitle)s", "Searching": "H\u013eadanie", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Zobrazi\u0165 zdroj", "Table of Contents": "Obsah", "This Page": "T\u00e1to str\u00e1nka", "Welcome! This is": "Vitajte! Toto je", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "V\u00e1\u0161mu h\u013eadaniu nezodpoved\u00e1 \u017eiadny dokument. Pros\u00edm, skontrolujte, \u017ee v\u0161etky zadan\u00e9 slov\u00e1 s\u00fa spr\u00e1vne nap\u00edsan\u00e9 a \u017ee ste zvolili vhodn\u00e9 kateg\u00f3rie.", "all functions, classes, terms": "v\u0161etky funkcie, triedy, term\u00edny", "can be huge": "m\u00f4\u017ee by\u0165 rozsiahle", "last updated": "posledn\u00e1 aktualiz\u00e1cia", "lists all sections and subsections": "zoznam v\u0161etk\u00fdch sekci\u00ed a podsekci\u00ed", "next chapter": "\u010fal\u0161ia kapitola", "previous chapter": "predo\u0161l\u00e1 kapitola", "quick access to all modules": "r\u00fdchly pr\u00edstup ku v\u0161etk\u00fdm modulom", "search": "h\u013eada\u0165", "search this documentation": "h\u013eada\u0165 v tejto dokument\u00e1cii", "the documentation for": "dokument\u00e1cia"}, "plural_expr": "(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "sk", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Copyright %(copyright)s.", + ", in ": ", v ", + "About these documents": "O dokument\u00e1cii", + "Automatically generated list of changes in version %(version)s": "Automaticky generovan\u00fd zoznam zmien vo verzii %(version)s", + "C API changes": "Zmeny API C", + "Changes in Version %(version)s — %(docstitle)s": "Zmeny vo verzii %(version)s — %(docstitle)s", + "Collapse sidebar": "Zbali\u0165 bo\u010dn\u00fd panel", + "Complete Table of Contents": "Celkov\u00fd obsah", + "Contents": "Obsah", + "Copyright": "Autorsk\u00e9 pr\u00e1vo", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Vytvoren\u00e9 pomocou <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Rozbali\u0165 bo\u010dn\u00fd panel", + "Full index on one page": "Cel\u00fd index na jednej strane", + "General Index": "V\u0161eobecn\u00fd index", + "Global Module Index": "Celkov\u00fd index modulov", + "Go": "OK", + "Hide Search Matches": "Skry\u0165 v\u00fdsledky h\u013eadania", + "Index": "Index", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "Indexov\u00e9 str\u00e1nky po p\u00edsmen\u00e1ch", + "Indices and tables:": "Indexy a tabu\u013eky", + "Last updated on %(last_updated)s.": "Naposledy aktualizovan\u00e9 %(last_updated)s.", + "Library changes": "Zmeny kni\u017enice", + "Navigation": "Navig\u00e1cia", + "Next topic": "\u010eal\u0161ia t\u00e9ma", + "Other changes": "Ostatn\u00e9 zmeny", + "Overview": "Preh\u013ead", + "Permalink to this definition": "Trval\u00fd odkaz na t\u00fato defin\u00edciu", + "Permalink to this headline": "Trval\u00fd odkaz na tento nadpis", + "Please activate JavaScript to enable the search\n functionality.": "Pros\u00edm, na zapnutie funkcie h\u013eadania,aktivujte\nJavaScript .", + "Preparing search...": "Pr\u00edprava h\u013eadania...", + "Previous topic": "Predo\u0161l\u00e1 t\u00e9ma", + "Quick search": "R\u00fdchle h\u013eadanie", + "Search": "H\u013eada\u0165", + "Search Page": "Str\u00e1nka h\u013eadania", + "Search Results": "V\u00fdsledky h\u013eadania", + "Search finished, found %s page(s) matching the search query.": "H\u013eadanie dokon\u010den\u00e9, n\u00e1jden\u00e9 %s strana(y), ktor\u00e9 vyhovuj\u00fa h\u013eadan\u00e9mu v\u00fdrazu.", + "Search within %(docstitle)s": "H\u013eada\u0165 v %(docstitle)s", + "Searching": "H\u013eadanie", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Zobrazi\u0165 zdroj", + "Table of Contents": "Obsah", + "This Page": "T\u00e1to str\u00e1nka", + "Welcome! This is": "Vitajte! Toto je", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "V\u00e1\u0161mu h\u013eadaniu nezodpoved\u00e1 \u017eiadny dokument. Pros\u00edm, skontrolujte, \u017ee v\u0161etky zadan\u00e9 slov\u00e1 s\u00fa spr\u00e1vne nap\u00edsan\u00e9 a \u017ee ste zvolili vhodn\u00e9 kateg\u00f3rie.", + "all functions, classes, terms": "v\u0161etky funkcie, triedy, term\u00edny", + "can be huge": "m\u00f4\u017ee by\u0165 rozsiahle", + "last updated": "posledn\u00e1 aktualiz\u00e1cia", + "lists all sections and subsections": "zoznam v\u0161etk\u00fdch sekci\u00ed a podsekci\u00ed", + "next chapter": "\u010fal\u0161ia kapitola", + "previous chapter": "predo\u0161l\u00e1 kapitola", + "quick access to all modules": "r\u00fdchly pr\u00edstup ku v\u0161etk\u00fdm modulom", + "search": "h\u013eada\u0165", + "search this documentation": "h\u013eada\u0165 v tejto dokument\u00e1cii", + "the documentation for": "dokument\u00e1cia" + }, + "plural_expr": "(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3)" +});
\ No newline at end of file diff --git a/sphinx/locale/sk/LC_MESSAGES/sphinx.po b/sphinx/locale/sk/LC_MESSAGES/sphinx.po index 7d4bb2118..07d654695 100644 --- a/sphinx/locale/sk/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sk/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # FIRST AUTHOR <EMAIL@ADDRESS>, 2008 # Slavko <linux@slavino.sk>, 2013-2019 diff --git a/sphinx/locale/sl/LC_MESSAGES/sphinx.js b/sphinx/locale/sl/LC_MESSAGES/sphinx.js index 668d230e7..87afdf542 100644 --- a/sphinx/locale/sl/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/sl/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "sl", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "O dokumentih", "Automatically generated list of changes in version %(version)s": "Avtomatsko generiran seznam sprememb v verziji %(version)s", "C API changes": "C API spremembe", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "Popoln Seznam Vsebine", "Contents": "", "Copyright": "Vse pravice pridr\u017eane", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Narejeno s <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "", "Full index on one page": "Poln indeks na eni strani", "General Index": "Splo\u0161ni abecedni seznam", "Global Module Index": "Splo\u0161en seznam modulov", "Go": "Potrdi", "Hide Search Matches": "Skrij resultate iskanja", "Index": "Abecedni seznam", "Index – %(key)s": "Seznam – %(key)s", "Index pages by letter": "Indeksiraj strani po \u010drki", "Indices and tables:": "Kazalo in seznami:", "Last updated on %(last_updated)s.": "Zadnji\u010d posodobljeno %(last_updated)s.", "Library changes": "Spremembe knji\u017enice", "Navigation": "Navigacija", "Next topic": "Naslednja tema", "Other changes": "Ostale spremembe", "Overview": "Pregled", "Permalink to this definition": "Povezava na to definicijo", "Permalink to this headline": "Povezava na naslov", "Please activate JavaScript to enable the search\n functionality.": "Za pravilno delovanje Iskanja morete vklopiti\n JavaScript.", "Preparing search...": "", "Previous topic": "Prej\u0161nja tema", "Quick search": "Hitro iskanje", "Search": "I\u0161\u010di", "Search Page": "Iskalnik", "Search Results": "Rezultati Iskanja", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "I\u0161\u010di med %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Prika\u017ei izvorno kodo", "Table of Contents": "", "This Page": "Trenutna stran", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "vse funkcije, razredi, izrazi", "can be huge": "lahko je veliko", "last updated": "", "lists all sections and subsections": "prikazi vse sekcije in podsekcije", "next chapter": "naslednje poglavje", "previous chapter": "prej\u0161nje poglavje", "quick access to all modules": "hiter dostop do vseh modulov", "search": "i\u0161\u010di", "search this documentation": "i\u0161\u010di po dokumentaciji", "the documentation for": ""}, "plural_expr": "(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "sl", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "O dokumentih", + "Automatically generated list of changes in version %(version)s": "Avtomatsko generiran seznam sprememb v verziji %(version)s", + "C API changes": "C API spremembe", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "Popoln Seznam Vsebine", + "Contents": "", + "Copyright": "Vse pravice pridr\u017eane", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Narejeno s <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "", + "Full index on one page": "Poln indeks na eni strani", + "General Index": "Splo\u0161ni abecedni seznam", + "Global Module Index": "Splo\u0161en seznam modulov", + "Go": "Potrdi", + "Hide Search Matches": "Skrij resultate iskanja", + "Index": "Abecedni seznam", + "Index – %(key)s": "Seznam – %(key)s", + "Index pages by letter": "Indeksiraj strani po \u010drki", + "Indices and tables:": "Kazalo in seznami:", + "Last updated on %(last_updated)s.": "Zadnji\u010d posodobljeno %(last_updated)s.", + "Library changes": "Spremembe knji\u017enice", + "Navigation": "Navigacija", + "Next topic": "Naslednja tema", + "Other changes": "Ostale spremembe", + "Overview": "Pregled", + "Permalink to this definition": "Povezava na to definicijo", + "Permalink to this headline": "Povezava na naslov", + "Please activate JavaScript to enable the search\n functionality.": "Za pravilno delovanje Iskanja morete vklopiti\n JavaScript.", + "Preparing search...": "", + "Previous topic": "Prej\u0161nja tema", + "Quick search": "Hitro iskanje", + "Search": "I\u0161\u010di", + "Search Page": "Iskalnik", + "Search Results": "Rezultati Iskanja", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "I\u0161\u010di med %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Prika\u017ei izvorno kodo", + "Table of Contents": "", + "This Page": "Trenutna stran", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "vse funkcije, razredi, izrazi", + "can be huge": "lahko je veliko", + "last updated": "", + "lists all sections and subsections": "prikazi vse sekcije in podsekcije", + "next chapter": "naslednje poglavje", + "previous chapter": "prej\u0161nje poglavje", + "quick access to all modules": "hiter dostop do vseh modulov", + "search": "i\u0161\u010di", + "search this documentation": "i\u0161\u010di po dokumentaciji", + "the documentation for": "" + }, + "plural_expr": "(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)" +});
\ No newline at end of file diff --git a/sphinx/locale/sl/LC_MESSAGES/sphinx.po b/sphinx/locale/sl/LC_MESSAGES/sphinx.po index 80dde8bd0..6ceca74a0 100644 --- a/sphinx/locale/sl/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sl/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/sq/LC_MESSAGES/sphinx.js b/sphinx/locale/sq/LC_MESSAGES/sphinx.js index de4b23098..7cb0a9e33 100644 --- a/sphinx/locale/sq/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/sq/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "sq", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">T\u00eb drejta kopjimi</a> %(copyright)s.", "© Copyright %(copyright)s.": "© T\u00eb drejta kopjimi %(copyright)s.", ", in ": "", "About these documents": "Mbi k\u00ebto dokumente", "Automatically generated list of changes in version %(version)s": "", "C API changes": "Ndryshime API C", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "Tkurre an\u00ebshtyll\u00ebn", "Complete Table of Contents": "Tryez\u00eb e Plot\u00eb e L\u00ebnd\u00ebs", "Contents": "L\u00ebnd\u00eb", "Copyright": "T\u00eb drejta kopjimi", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "Zgjeroje an\u00ebshtyll\u00ebn", "Full index on one page": "Tregues i plot\u00eb n\u00eb nj\u00eb faqe", "General Index": "Tregues i P\u00ebrgjithsh\u00ebm", "Global Module Index": "Tregues Global Modulesh", "Go": "", "Hide Search Matches": "Fshih P\u00ebrputhje K\u00ebrkimi", "Index": "Tregues", "Index – %(key)s": "Tregues – %(key)s", "Index pages by letter": "Faqe treguesi sipas shkronjash", "Indices and tables:": "Tregues dhe tabela:", "Last updated on %(last_updated)s.": "P\u00ebrdit\u00ebsuar s\u00eb fundi m\u00eb %(last_updated)s.", "Library changes": "Ndryshime librarie", "Navigation": "L\u00ebvizje", "Next topic": "Subjekti pasues", "Other changes": "Ndryshime t\u00eb tjera", "Overview": "P\u00ebrmbledhje", "Permalink to this definition": "Permalidhje p\u00ebr te ky p\u00ebrkufizim", "Permalink to this headline": "Permalidhje te ky titull", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "Po p\u00ebrgatitet k\u00ebrkim...", "Previous topic": "Subjekti i m\u00ebparsh\u00ebm", "Quick search": "K\u00ebrkim i shpejt\u00eb", "Search": "", "Search Page": "Faqe K\u00ebrkimesh", "Search Results": "P\u00ebrfundime K\u00ebrkimi", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "K\u00ebrkoni brenda %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Shfaq Burimin", "Table of Contents": "Tryeza e L\u00ebnd\u00ebs", "This Page": "Kjo Faqe", "Welcome! This is": "Mir\u00eb se vini! Ky \u00ebsht\u00eb", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "krejt funksionet, klasat, termat", "can be huge": "mund t\u00eb jet\u00eb i st\u00ebrmadh", "last updated": "p\u00ebrdit\u00ebsuar s\u00eb fundi m\u00eb", "lists all sections and subsections": "paraqet krejt ndarjet dhe n\u00ebnndarjet", "next chapter": "kapitulli pasues", "previous chapter": "kapitulli i m\u00ebparsh\u00ebm", "quick access to all modules": "hyrje e shpejt\u00eb te krejt modulet", "search": "k\u00ebrko", "search this documentation": "k\u00ebrkoni te ky dokumentim", "the documentation for": "dokumentimi p\u00ebr"}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "sq", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">T\u00eb drejta kopjimi</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© T\u00eb drejta kopjimi %(copyright)s.", + ", in ": "", + "About these documents": "Mbi k\u00ebto dokumente", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "Ndryshime API C", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "Tkurre an\u00ebshtyll\u00ebn", + "Complete Table of Contents": "Tryez\u00eb e Plot\u00eb e L\u00ebnd\u00ebs", + "Contents": "L\u00ebnd\u00eb", + "Copyright": "T\u00eb drejta kopjimi", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "Zgjeroje an\u00ebshtyll\u00ebn", + "Full index on one page": "Tregues i plot\u00eb n\u00eb nj\u00eb faqe", + "General Index": "Tregues i P\u00ebrgjithsh\u00ebm", + "Global Module Index": "Tregues Global Modulesh", + "Go": "", + "Hide Search Matches": "Fshih P\u00ebrputhje K\u00ebrkimi", + "Index": "Tregues", + "Index – %(key)s": "Tregues – %(key)s", + "Index pages by letter": "Faqe treguesi sipas shkronjash", + "Indices and tables:": "Tregues dhe tabela:", + "Last updated on %(last_updated)s.": "P\u00ebrdit\u00ebsuar s\u00eb fundi m\u00eb %(last_updated)s.", + "Library changes": "Ndryshime librarie", + "Navigation": "L\u00ebvizje", + "Next topic": "Subjekti pasues", + "Other changes": "Ndryshime t\u00eb tjera", + "Overview": "P\u00ebrmbledhje", + "Permalink to this definition": "Permalidhje p\u00ebr te ky p\u00ebrkufizim", + "Permalink to this headline": "Permalidhje te ky titull", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "Po p\u00ebrgatitet k\u00ebrkim...", + "Previous topic": "Subjekti i m\u00ebparsh\u00ebm", + "Quick search": "K\u00ebrkim i shpejt\u00eb", + "Search": "", + "Search Page": "Faqe K\u00ebrkimesh", + "Search Results": "P\u00ebrfundime K\u00ebrkimi", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "K\u00ebrkoni brenda %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Shfaq Burimin", + "Table of Contents": "Tryeza e L\u00ebnd\u00ebs", + "This Page": "Kjo Faqe", + "Welcome! This is": "Mir\u00eb se vini! Ky \u00ebsht\u00eb", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "krejt funksionet, klasat, termat", + "can be huge": "mund t\u00eb jet\u00eb i st\u00ebrmadh", + "last updated": "p\u00ebrdit\u00ebsuar s\u00eb fundi m\u00eb", + "lists all sections and subsections": "paraqet krejt ndarjet dhe n\u00ebnndarjet", + "next chapter": "kapitulli pasues", + "previous chapter": "kapitulli i m\u00ebparsh\u00ebm", + "quick access to all modules": "hyrje e shpejt\u00eb te krejt modulet", + "search": "k\u00ebrko", + "search this documentation": "k\u00ebrkoni te ky dokumentim", + "the documentation for": "dokumentimi p\u00ebr" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/sq/LC_MESSAGES/sphinx.po b/sphinx/locale/sq/LC_MESSAGES/sphinx.po index bf21f378d..fb1b0e26c 100644 --- a/sphinx/locale/sq/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sq/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/sr/LC_MESSAGES/sphinx.js b/sphinx/locale/sr/LC_MESSAGES/sphinx.js index d1b310c1e..f4128343a 100644 --- a/sphinx/locale/sr/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/sr/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "sr", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0458\u0430", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "\u043d\u0430\u0440\u0435\u0434\u043d\u0430 \u0433\u043b\u0430\u0432\u0430", "previous chapter": "\u043f\u0440\u0435\u0442\u0445\u043e\u0434\u043d\u0430 \u0433\u043b\u0430\u0432\u0430", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "sr", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0458\u0430", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "\u043d\u0430\u0440\u0435\u0434\u043d\u0430 \u0433\u043b\u0430\u0432\u0430", + "previous chapter": "\u043f\u0440\u0435\u0442\u0445\u043e\u0434\u043d\u0430 \u0433\u043b\u0430\u0432\u0430", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)" +});
\ No newline at end of file diff --git a/sphinx/locale/sr/LC_MESSAGES/sphinx.po b/sphinx/locale/sr/LC_MESSAGES/sphinx.po index 1df55881c..2bcfcf51c 100644 --- a/sphinx/locale/sr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sr/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Risto Pejasinovic <risto.pejasinovic@gmail.com>, 2019 msgid "" diff --git a/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.js b/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.js index 58a89c7a6..600ecedb4 100644 --- a/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "sr", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "sr", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)" +});
\ No newline at end of file diff --git a/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po b/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po index a7b82e633..574d218de 100644 --- a/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.js b/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.js index ae9570f60..15c106401 100644 --- a/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "sr_Cyrl_RS", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "sr_Cyrl_RS", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)" +});
\ No newline at end of file diff --git a/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po b/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po index dad4f3542..3e7ac5ba4 100644 --- a/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/sv/LC_MESSAGES/sphinx.js b/sphinx/locale/sv/LC_MESSAGES/sphinx.js index aed941f5d..d0d65cb4d 100644 --- a/sphinx/locale/sv/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/sv/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "sv", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "Om dessa dokument", "Automatically generated list of changes in version %(version)s": "Automatiskt genererad lista \u00f6ver f\u00f6r\u00e4ndringar i version %(version)s", "C API changes": "F\u00f6r\u00e4ndringar i C-API", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "D\u00f6lj sidolist", "Complete Table of Contents": "Komplett Inneh\u00e5llsf\u00f6rteckning", "Contents": "Inneh\u00e5ll", "Copyright": "Copyright", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Skapad med <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "Expandera sidolist", "Full index on one page": "Hela inneh\u00e5llsf\u00f6rteckningen p\u00e5 en sida", "General Index": "Huvudindex", "Global Module Index": "Global Modulindex", "Go": "G\u00e5", "Hide Search Matches": "D\u00f6lj S\u00f6kresultat", "Index": "Index", "Index – %(key)s": "Index – %(key)s", "Index pages by letter": "Inneh\u00e5llsf\u00f6rteckning per inledande bokstav", "Indices and tables:": "Index och tabeller", "Last updated on %(last_updated)s.": "Senast uppdaterad %(last_updated)s.", "Library changes": "F\u00f6r\u00e4ndringar i bibliotek", "Navigation": "Navigation", "Next topic": "N\u00e4sta titel", "Other changes": "\u00d6vriga f\u00f6r\u00e4ndringar", "Overview": "\u00d6versikt", "Permalink to this definition": "Permalink till denna definition", "Permalink to this headline": "Permalink till denna rubrik", "Please activate JavaScript to enable the search\n functionality.": "Var god aktivera JavaScript f\u00f6r s\u00f6kfunktionalitet.", "Preparing search...": "", "Previous topic": "F\u00f6reg\u00e5ende titel", "Quick search": "Snabbs\u00f6k", "Search": "S\u00f6k", "Search Page": "S\u00f6ksida", "Search Results": "S\u00f6kresultat", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "S\u00f6k bland %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Visa k\u00e4llfil", "Table of Contents": "", "This Page": "Denna Sida", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "alla funktioner, klasser, villkor", "can be huge": "kan bli stort", "last updated": "", "lists all sections and subsections": "lista \u00f6ver alla paragrafer och underparagrafer", "next chapter": "N\u00e4sta kapitel", "previous chapter": "F\u00f6reg\u00e5ende kapitel", "quick access to all modules": "genv\u00e4g till alla moduler", "search": "s\u00f6k", "search this documentation": "s\u00f6k i det h\u00e4r dokumentet", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "sv", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "Om dessa dokument", + "Automatically generated list of changes in version %(version)s": "Automatiskt genererad lista \u00f6ver f\u00f6r\u00e4ndringar i version %(version)s", + "C API changes": "F\u00f6r\u00e4ndringar i C-API", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "D\u00f6lj sidolist", + "Complete Table of Contents": "Komplett Inneh\u00e5llsf\u00f6rteckning", + "Contents": "Inneh\u00e5ll", + "Copyright": "Copyright", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "Skapad med <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "Expandera sidolist", + "Full index on one page": "Hela inneh\u00e5llsf\u00f6rteckningen p\u00e5 en sida", + "General Index": "Huvudindex", + "Global Module Index": "Global Modulindex", + "Go": "G\u00e5", + "Hide Search Matches": "D\u00f6lj S\u00f6kresultat", + "Index": "Index", + "Index – %(key)s": "Index – %(key)s", + "Index pages by letter": "Inneh\u00e5llsf\u00f6rteckning per inledande bokstav", + "Indices and tables:": "Index och tabeller", + "Last updated on %(last_updated)s.": "Senast uppdaterad %(last_updated)s.", + "Library changes": "F\u00f6r\u00e4ndringar i bibliotek", + "Navigation": "Navigation", + "Next topic": "N\u00e4sta titel", + "Other changes": "\u00d6vriga f\u00f6r\u00e4ndringar", + "Overview": "\u00d6versikt", + "Permalink to this definition": "Permalink till denna definition", + "Permalink to this headline": "Permalink till denna rubrik", + "Please activate JavaScript to enable the search\n functionality.": "Var god aktivera JavaScript f\u00f6r s\u00f6kfunktionalitet.", + "Preparing search...": "", + "Previous topic": "F\u00f6reg\u00e5ende titel", + "Quick search": "Snabbs\u00f6k", + "Search": "S\u00f6k", + "Search Page": "S\u00f6ksida", + "Search Results": "S\u00f6kresultat", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "S\u00f6k bland %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Visa k\u00e4llfil", + "Table of Contents": "", + "This Page": "Denna Sida", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "alla funktioner, klasser, villkor", + "can be huge": "kan bli stort", + "last updated": "", + "lists all sections and subsections": "lista \u00f6ver alla paragrafer och underparagrafer", + "next chapter": "N\u00e4sta kapitel", + "previous chapter": "F\u00f6reg\u00e5ende kapitel", + "quick access to all modules": "genv\u00e4g till alla moduler", + "search": "s\u00f6k", + "search this documentation": "s\u00f6k i det h\u00e4r dokumentet", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/sv/LC_MESSAGES/sphinx.po b/sphinx/locale/sv/LC_MESSAGES/sphinx.po index bbf5e5ff1..af26ab2f1 100644 --- a/sphinx/locale/sv/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sv/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/ta/LC_MESSAGES/sphinx.js b/sphinx/locale/ta/LC_MESSAGES/sphinx.js index b5a1a8080..051abfb6f 100644 --- a/sphinx/locale/ta/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ta/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ta", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ta", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/ta/LC_MESSAGES/sphinx.po b/sphinx/locale/ta/LC_MESSAGES/sphinx.po index bb1c77f28..cc19b6dfa 100644 --- a/sphinx/locale/ta/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ta/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Julien Malard <julien.malard@mail.mcgill.ca>, 2019 msgid "" diff --git a/sphinx/locale/te/LC_MESSAGES/sphinx.js b/sphinx/locale/te/LC_MESSAGES/sphinx.js index 6de6a68e3..fd7b372ad 100644 --- a/sphinx/locale/te/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/te/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "te", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "te", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/te/LC_MESSAGES/sphinx.po b/sphinx/locale/te/LC_MESSAGES/sphinx.po index c6c3c45f1..32c1fc59e 100644 --- a/sphinx/locale/te/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/te/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/tr/LC_MESSAGES/sphinx.js b/sphinx/locale/tr/LC_MESSAGES/sphinx.js index 984176f66..3292571e9 100644 --- a/sphinx/locale/tr/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/tr/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "tr", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Telif hakk\u0131</a> %(copyright)s.", "© Copyright %(copyright)s.": "© Telif hakk\u0131 %(copyright)s.", ", in ": ", \u015funun i\u00e7inde:", "About these documents": "Bu belgeler hakk\u0131nda", "Automatically generated list of changes in version %(version)s": "%(version)s s\u00fcr\u00fcm\u00fcndeki de\u011fi\u015fikliklerin otomatik olarak \u00fcretilmi\u015f listesi", "C API changes": "C API'sindeki de\u011fi\u015fiklikler", "Changes in Version %(version)s — %(docstitle)s": "S\u00fcr\u00fcm %(version)s — %(docstitle)s i\u00e7indeki De\u011fi\u015fiklikler", "Collapse sidebar": "Yan \u00e7ubu\u011fu daralt", "Complete Table of Contents": "Tam \u0130\u00e7indekiler", "Contents": "\u0130\u00e7indekiler", "Copyright": "Telif hakk\u0131", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s kullan\u0131larak olu\u015fturuldu.", "Expand sidebar": "Yan \u00e7ubu\u011fu geni\u015flet", "Full index on one page": "Tek sayfada tam dizin", "General Index": "Genel Dizin", "Global Module Index": "Genel Mod\u00fcl Dizini", "Go": "Git", "Hide Search Matches": "Arama E\u015fle\u015fmelerini Gizle", "Index": "Dizin", "Index – %(key)s": "Dizin – %(key)s", "Index pages by letter": "Harfe g\u00f6re dizin sayfalar\u0131", "Indices and tables:": "Dizinler ve tablolar:", "Last updated on %(last_updated)s.": "Son g\u00fcncelleme: %(last_updated)s.", "Library changes": "K\u00fct\u00fcphane de\u011fi\u015fiklikleri", "Navigation": "Gezinti", "Next topic": "Sonraki konu", "Other changes": "Di\u011fer de\u011fi\u015fiklikler", "Overview": "Genel Bak\u0131\u015f", "Permalink to this definition": "Bu tan\u0131m i\u00e7in kal\u0131c\u0131 ba\u011flant\u0131", "Permalink to this headline": "Bu ba\u015fl\u0131k i\u00e7in kal\u0131c\u0131 ba\u011flant\u0131", "Please activate JavaScript to enable the search\n functionality.": "Arama i\u015flevini kullanabilmek i\u00e7in l\u00fctfen JavaScript'i\n etkinle\u015ftirin.", "Preparing search...": "Aramaya haz\u0131rlan\u0131yor...", "Previous topic": "\u00d6nceki konu", "Quick search": "H\u0131zl\u0131 Arama", "Search": "Ara", "Search Page": "Arama Sayfas\u0131", "Search Results": "Arama Sonu\u00e7lar\u0131", "Search finished, found %s page(s) matching the search query.": "Arama tamamland\u0131. Sorguyu i\u00e7eren %s sayfa bulundu.", "Search within %(docstitle)s": "%(docstitle)s i\u00e7inde ara", "Searching": "Aran\u0131yor", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Kayna\u011f\u0131 G\u00f6ster", "Table of Contents": "\u0130\u00e7indekiler", "This Page": "Bu Sayfa", "Welcome! This is": "Ho\u015f Geldiniz! Kar\u015f\u0131n\u0131zda", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Arama sonucunda herhangi bir belge bulunamad\u0131. B\u00fct\u00fcn kelimeleri do\u011fru yazd\u0131\u011f\u0131n\u0131zdan ve gerekli b\u00fct\u00fcn kategorileri se\u00e7ti\u011finizden emin olun.", "all functions, classes, terms": "t\u00fcm i\u015flevler, s\u0131n\u0131flar, terimler", "can be huge": "\u00e7ok b\u00fcy\u00fck olabilir", "last updated": "son g\u00fcncelleme", "lists all sections and subsections": "t\u00fcm b\u00f6l\u00fcmleri ve alt b\u00f6l\u00fcmleri listeler", "next chapter": "sonraki b\u00f6l\u00fcm", "previous chapter": "\u00f6nceki b\u00f6l\u00fcm", "quick access to all modules": "t\u00fcm mod\u00fcllere h\u0131zl\u0131 eri\u015fim", "search": "ara", "search this documentation": "bu belgelendirmeyi ara", "the documentation for": "belgelendirme konusu: "}, "plural_expr": "(n > 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "tr", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">Telif hakk\u0131</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© Telif hakk\u0131 %(copyright)s.", + ", in ": ", \u015funun i\u00e7inde:", + "About these documents": "Bu belgeler hakk\u0131nda", + "Automatically generated list of changes in version %(version)s": "%(version)s s\u00fcr\u00fcm\u00fcndeki de\u011fi\u015fikliklerin otomatik olarak \u00fcretilmi\u015f listesi", + "C API changes": "C API'sindeki de\u011fi\u015fiklikler", + "Changes in Version %(version)s — %(docstitle)s": "S\u00fcr\u00fcm %(version)s — %(docstitle)s i\u00e7indeki De\u011fi\u015fiklikler", + "Collapse sidebar": "Yan \u00e7ubu\u011fu daralt", + "Complete Table of Contents": "Tam \u0130\u00e7indekiler", + "Contents": "\u0130\u00e7indekiler", + "Copyright": "Telif hakk\u0131", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "<a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s kullan\u0131larak olu\u015fturuldu.", + "Expand sidebar": "Yan \u00e7ubu\u011fu geni\u015flet", + "Full index on one page": "Tek sayfada tam dizin", + "General Index": "Genel Dizin", + "Global Module Index": "Genel Mod\u00fcl Dizini", + "Go": "Git", + "Hide Search Matches": "Arama E\u015fle\u015fmelerini Gizle", + "Index": "Dizin", + "Index – %(key)s": "Dizin – %(key)s", + "Index pages by letter": "Harfe g\u00f6re dizin sayfalar\u0131", + "Indices and tables:": "Dizinler ve tablolar:", + "Last updated on %(last_updated)s.": "Son g\u00fcncelleme: %(last_updated)s.", + "Library changes": "K\u00fct\u00fcphane de\u011fi\u015fiklikleri", + "Navigation": "Gezinti", + "Next topic": "Sonraki konu", + "Other changes": "Di\u011fer de\u011fi\u015fiklikler", + "Overview": "Genel Bak\u0131\u015f", + "Permalink to this definition": "Bu tan\u0131m i\u00e7in kal\u0131c\u0131 ba\u011flant\u0131", + "Permalink to this headline": "Bu ba\u015fl\u0131k i\u00e7in kal\u0131c\u0131 ba\u011flant\u0131", + "Please activate JavaScript to enable the search\n functionality.": "Arama i\u015flevini kullanabilmek i\u00e7in l\u00fctfen JavaScript'i\n etkinle\u015ftirin.", + "Preparing search...": "Aramaya haz\u0131rlan\u0131yor...", + "Previous topic": "\u00d6nceki konu", + "Quick search": "H\u0131zl\u0131 Arama", + "Search": "Ara", + "Search Page": "Arama Sayfas\u0131", + "Search Results": "Arama Sonu\u00e7lar\u0131", + "Search finished, found %s page(s) matching the search query.": "Arama tamamland\u0131. Sorguyu i\u00e7eren %s sayfa bulundu.", + "Search within %(docstitle)s": "%(docstitle)s i\u00e7inde ara", + "Searching": "Aran\u0131yor", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Kayna\u011f\u0131 G\u00f6ster", + "Table of Contents": "\u0130\u00e7indekiler", + "This Page": "Bu Sayfa", + "Welcome! This is": "Ho\u015f Geldiniz! Kar\u015f\u0131n\u0131zda", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Arama sonucunda herhangi bir belge bulunamad\u0131. B\u00fct\u00fcn kelimeleri do\u011fru yazd\u0131\u011f\u0131n\u0131zdan ve gerekli b\u00fct\u00fcn kategorileri se\u00e7ti\u011finizden emin olun.", + "all functions, classes, terms": "t\u00fcm i\u015flevler, s\u0131n\u0131flar, terimler", + "can be huge": "\u00e7ok b\u00fcy\u00fck olabilir", + "last updated": "son g\u00fcncelleme", + "lists all sections and subsections": "t\u00fcm b\u00f6l\u00fcmleri ve alt b\u00f6l\u00fcmleri listeler", + "next chapter": "sonraki b\u00f6l\u00fcm", + "previous chapter": "\u00f6nceki b\u00f6l\u00fcm", + "quick access to all modules": "t\u00fcm mod\u00fcllere h\u0131zl\u0131 eri\u015fim", + "search": "ara", + "search this documentation": "bu belgelendirmeyi ara", + "the documentation for": "belgelendirme konusu: " + }, + "plural_expr": "(n > 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/tr/LC_MESSAGES/sphinx.po b/sphinx/locale/tr/LC_MESSAGES/sphinx.po index 996d6e67c..b37c18d50 100644 --- a/sphinx/locale/tr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/tr/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # BouRock, 2020 # Fırat Özgül <ozgulfirat@gmail.com>, 2013-2016 diff --git a/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.js b/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.js index 48b4cacde..2228a0d48 100644 --- a/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "uk_UA", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "\u041f\u0440\u043e \u0446\u0456 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438", "Automatically generated list of changes in version %(version)s": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u0437\u0433\u0435\u043d\u0435\u0440\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u043c\u0456\u043d \u0432 \u0432\u0435\u0440\u0441\u0456\u0457 %(version)s", "C API changes": "\u0437\u043c\u0456\u043d\u0438 C API", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "\u041f\u043e\u0432\u043d\u0438\u0439 \u0417\u043c\u0456\u0441\u0442", "Contents": "", "Copyright": "\u0410\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0456 \u043f\u0440\u0430\u0432\u0430", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u0421\u0442\u0432\u043e\u0440\u0435\u043d\u043e \u0437 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u044f\u043c <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "", "Full index on one page": "\u041f\u043e\u0432\u043d\u0438\u0439 \u0456\u043d\u0434\u0435\u043a\u0441 \u043d\u0430 \u043e\u0434\u043d\u0456\u0439 \u0441\u0442\u043e\u0440\u0456\u043d\u0446\u0456", "General Index": "\u0417\u0430\u0433\u0430\u043b\u044c\u043d\u0438\u0439 \u0456\u043d\u0434\u0435\u043a\u0441", "Global Module Index": "\u0417\u0430\u0433\u0430\u043b\u044c\u043d\u0438\u0439 \u0456\u043d\u0434\u0435\u043a\u0441 \u043c\u043e\u0434\u0443\u043b\u0456\u0432", "Go": "\u0412\u043f\u0435\u0440\u0435\u0434", "Hide Search Matches": "\u041f\u0440\u0438\u0445\u043e\u0432\u0430\u0442\u0438 \u0441\u043f\u0456\u0432\u043f\u0430\u0434\u0456\u043d\u043d\u044f \u043f\u043e\u0448\u0443\u043a\u0443", "Index": "\u0406\u043d\u0434\u0435\u043a\u0441", "Index – %(key)s": "\u0406\u043d\u0434\u0435\u043a\u0441 – %(key)s", "Index pages by letter": "\u0406\u043d\u0434\u0435\u043a\u0441\u043d\u0456 \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0438 \u043f\u043e \u0441\u0438\u043c\u0432\u043e\u043b\u0430\u043c", "Indices and tables:": "\u0406\u043d\u0434\u0435\u043a\u0441\u0438 \u0442\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0456:", "Last updated on %(last_updated)s.": "\u0412\u043e\u0441\u0442\u0430\u043d\u043d\u0454 \u043e\u043d\u043e\u0432\u043b\u0435\u043d\u043e %(last_updated)s.", "Library changes": "\u0417\u043c\u0456\u043d\u0438 \u0432 \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u0446\u0456", "Navigation": "\u041d\u0430\u0432\u0456\u0433\u0430\u0446\u0456\u044f", "Next topic": "\u041d\u0430\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u0435\u043c\u0430", "Other changes": "\u0406\u043d\u0448\u0456 \u0437\u043c\u0456\u043d\u0438", "Overview": "\u041e\u0433\u043b\u044f\u0434", "Permalink to this definition": "\u041f\u043e\u0441\u0442\u0456\u0439\u043d\u0435 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f \u043d\u0430 \u0446\u0435 \u0432\u0438\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f", "Permalink to this headline": "\u041f\u043e\u0441\u0442\u0456\u0439\u043d\u0435 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f \u043d\u0430 \u0446\u0435\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a", "Please activate JavaScript to enable the search\n functionality.": "\u0411\u0443\u0434\u044c-\u043b\u0430\u0441\u043a\u0430 \u0432\u0456\u043c\u043a\u043d\u0456\u0442\u044c \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u043a\u0443 JavaScript, \u0449\u043e\u0431 \u0432\u0432\u0456\u043a\u043d\u0443\u0442\u0438\n\"\n\" \u043f\u043e\u0448\u0443\u043a.", "Preparing search...": "", "Previous topic": "\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0456\u0439 \u0440\u043e\u0437\u0434\u0456\u043b", "Quick search": "\u0428\u0432\u0438\u0434\u043a\u0438\u0439 \u043f\u043e\u0448\u0443\u043a", "Search": "\u041f\u043e\u0448\u0443\u043a", "Search Page": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043f\u043e\u0448\u0443\u043a\u0443", "Search Results": "\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0438 \u043f\u043e\u0448\u0443\u043a\u0443", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "\u0428\u0443\u043a\u0430\u0442\u0438 \u0432 %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u0412\u0456\u0434\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u0438 \u0432\u0438\u0445\u0456\u0434\u043d\u0438\u0439 \u0442\u0435\u043a\u0441\u0442", "Table of Contents": "", "This Page": "\u0426\u044f \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0430", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "\u0432\u0441\u0456 \u0444\u0443\u043d\u043a\u0446\u0456\u0457, \u043a\u043b\u0430\u0441\u0438, \u0442\u0435\u0440\u043c\u0456\u043d\u0438", "can be huge": "\u043c\u043e\u0436\u0435 \u0431\u0443\u0442\u0438 \u0432\u0435\u043b\u0438\u0447\u0435\u0437\u043d\u0438\u043c", "last updated": "", "lists all sections and subsections": "\u043f\u0435\u0440\u0435\u043b\u0456\u0447\u0438\u0442\u0438 \u0432\u0441\u0456 \u0441\u0435\u043a\u0446\u0456\u0457 \u0442\u0430 \u043f\u0456\u0434\u0441\u0435\u043a\u0446\u0456\u0457", "next chapter": "\u043d\u0430\u0441\u0442\u0443\u043f\u043d\u0438\u0439 \u0440\u043e\u0437\u0434\u0456\u043b", "previous chapter": "\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0456\u0439 \u0440\u043e\u0437\u0434\u0456\u043b", "quick access to all modules": "\u0448\u0432\u0438\u0434\u043a\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u0432\u0441\u0456\u0445 \u043c\u043e\u0434\u0443\u043b\u0456\u0432", "search": "\u043f\u043e\u0448\u0443\u043a", "search this documentation": "\u0448\u0443\u043a\u0430\u0442\u0438 \u0446\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0456\u044e", "the documentation for": ""}, "plural_expr": "(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "uk_UA", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "\u041f\u0440\u043e \u0446\u0456 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438", + "Automatically generated list of changes in version %(version)s": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u0437\u0433\u0435\u043d\u0435\u0440\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u043c\u0456\u043d \u0432 \u0432\u0435\u0440\u0441\u0456\u0457 %(version)s", + "C API changes": "\u0437\u043c\u0456\u043d\u0438 C API", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "\u041f\u043e\u0432\u043d\u0438\u0439 \u0417\u043c\u0456\u0441\u0442", + "Contents": "", + "Copyright": "\u0410\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0456 \u043f\u0440\u0430\u0432\u0430", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u0421\u0442\u0432\u043e\u0440\u0435\u043d\u043e \u0437 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u0430\u043d\u043d\u044f\u043c <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "", + "Full index on one page": "\u041f\u043e\u0432\u043d\u0438\u0439 \u0456\u043d\u0434\u0435\u043a\u0441 \u043d\u0430 \u043e\u0434\u043d\u0456\u0439 \u0441\u0442\u043e\u0440\u0456\u043d\u0446\u0456", + "General Index": "\u0417\u0430\u0433\u0430\u043b\u044c\u043d\u0438\u0439 \u0456\u043d\u0434\u0435\u043a\u0441", + "Global Module Index": "\u0417\u0430\u0433\u0430\u043b\u044c\u043d\u0438\u0439 \u0456\u043d\u0434\u0435\u043a\u0441 \u043c\u043e\u0434\u0443\u043b\u0456\u0432", + "Go": "\u0412\u043f\u0435\u0440\u0435\u0434", + "Hide Search Matches": "\u041f\u0440\u0438\u0445\u043e\u0432\u0430\u0442\u0438 \u0441\u043f\u0456\u0432\u043f\u0430\u0434\u0456\u043d\u043d\u044f \u043f\u043e\u0448\u0443\u043a\u0443", + "Index": "\u0406\u043d\u0434\u0435\u043a\u0441", + "Index – %(key)s": "\u0406\u043d\u0434\u0435\u043a\u0441 – %(key)s", + "Index pages by letter": "\u0406\u043d\u0434\u0435\u043a\u0441\u043d\u0456 \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0438 \u043f\u043e \u0441\u0438\u043c\u0432\u043e\u043b\u0430\u043c", + "Indices and tables:": "\u0406\u043d\u0434\u0435\u043a\u0441\u0438 \u0442\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0456:", + "Last updated on %(last_updated)s.": "\u0412\u043e\u0441\u0442\u0430\u043d\u043d\u0454 \u043e\u043d\u043e\u0432\u043b\u0435\u043d\u043e %(last_updated)s.", + "Library changes": "\u0417\u043c\u0456\u043d\u0438 \u0432 \u0431\u0456\u0431\u043b\u0456\u043e\u0442\u0435\u0446\u0456", + "Navigation": "\u041d\u0430\u0432\u0456\u0433\u0430\u0446\u0456\u044f", + "Next topic": "\u041d\u0430\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u0435\u043c\u0430", + "Other changes": "\u0406\u043d\u0448\u0456 \u0437\u043c\u0456\u043d\u0438", + "Overview": "\u041e\u0433\u043b\u044f\u0434", + "Permalink to this definition": "\u041f\u043e\u0441\u0442\u0456\u0439\u043d\u0435 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f \u043d\u0430 \u0446\u0435 \u0432\u0438\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f", + "Permalink to this headline": "\u041f\u043e\u0441\u0442\u0456\u0439\u043d\u0435 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f \u043d\u0430 \u0446\u0435\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a", + "Please activate JavaScript to enable the search\n functionality.": "\u0411\u0443\u0434\u044c-\u043b\u0430\u0441\u043a\u0430 \u0432\u0456\u043c\u043a\u043d\u0456\u0442\u044c \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u043a\u0443 JavaScript, \u0449\u043e\u0431 \u0432\u0432\u0456\u043a\u043d\u0443\u0442\u0438\n\"\n\" \u043f\u043e\u0448\u0443\u043a.", + "Preparing search...": "", + "Previous topic": "\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0456\u0439 \u0440\u043e\u0437\u0434\u0456\u043b", + "Quick search": "\u0428\u0432\u0438\u0434\u043a\u0438\u0439 \u043f\u043e\u0448\u0443\u043a", + "Search": "\u041f\u043e\u0448\u0443\u043a", + "Search Page": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043f\u043e\u0448\u0443\u043a\u0443", + "Search Results": "\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0438 \u043f\u043e\u0448\u0443\u043a\u0443", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "\u0428\u0443\u043a\u0430\u0442\u0438 \u0432 %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u0412\u0456\u0434\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u0438 \u0432\u0438\u0445\u0456\u0434\u043d\u0438\u0439 \u0442\u0435\u043a\u0441\u0442", + "Table of Contents": "", + "This Page": "\u0426\u044f \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0430", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "\u0432\u0441\u0456 \u0444\u0443\u043d\u043a\u0446\u0456\u0457, \u043a\u043b\u0430\u0441\u0438, \u0442\u0435\u0440\u043c\u0456\u043d\u0438", + "can be huge": "\u043c\u043e\u0436\u0435 \u0431\u0443\u0442\u0438 \u0432\u0435\u043b\u0438\u0447\u0435\u0437\u043d\u0438\u043c", + "last updated": "", + "lists all sections and subsections": "\u043f\u0435\u0440\u0435\u043b\u0456\u0447\u0438\u0442\u0438 \u0432\u0441\u0456 \u0441\u0435\u043a\u0446\u0456\u0457 \u0442\u0430 \u043f\u0456\u0434\u0441\u0435\u043a\u0446\u0456\u0457", + "next chapter": "\u043d\u0430\u0441\u0442\u0443\u043f\u043d\u0438\u0439 \u0440\u043e\u0437\u0434\u0456\u043b", + "previous chapter": "\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0456\u0439 \u0440\u043e\u0437\u0434\u0456\u043b", + "quick access to all modules": "\u0448\u0432\u0438\u0434\u043a\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u0432\u0441\u0456\u0445 \u043c\u043e\u0434\u0443\u043b\u0456\u0432", + "search": "\u043f\u043e\u0448\u0443\u043a", + "search this documentation": "\u0448\u0443\u043a\u0430\u0442\u0438 \u0446\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0456\u044e", + "the documentation for": "" + }, + "plural_expr": "(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3)" +});
\ No newline at end of file diff --git a/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po b/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po index 2b43faa32..791426dd7 100644 --- a/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Petro Sasnyk <petro@sasnyk.name>, 2009 msgid "" diff --git a/sphinx/locale/ur/LC_MESSAGES/sphinx.js b/sphinx/locale/ur/LC_MESSAGES/sphinx.js index d97879dfc..90f79f16f 100644 --- a/sphinx/locale/ur/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/ur/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "ur", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "", "Contents": "", "Copyright": "", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", "Expand sidebar": "", "Full index on one page": "", "General Index": "", "Global Module Index": "", "Go": "", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "", "Index pages by letter": "", "Indices and tables:": "", "Last updated on %(last_updated)s.": "", "Library changes": "", "Navigation": "", "Next topic": "", "Other changes": "", "Overview": "", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "", "Preparing search...": "", "Previous topic": "", "Quick search": "", "Search": "", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "", "Table of Contents": "", "This Page": "", "Welcome! This is": "", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "", "can be huge": "", "last updated": "", "lists all sections and subsections": "", "next chapter": "", "previous chapter": "", "quick access to all modules": "", "search": "", "search this documentation": "", "the documentation for": ""}, "plural_expr": "(n != 1)"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "ur", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "", + "Contents": "", + "Copyright": "", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "", + "Expand sidebar": "", + "Full index on one page": "", + "General Index": "", + "Global Module Index": "", + "Go": "", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "", + "Index pages by letter": "", + "Indices and tables:": "", + "Last updated on %(last_updated)s.": "", + "Library changes": "", + "Navigation": "", + "Next topic": "", + "Other changes": "", + "Overview": "", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "", + "Preparing search...": "", + "Previous topic": "", + "Quick search": "", + "Search": "", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "", + "can be huge": "", + "last updated": "", + "lists all sections and subsections": "", + "next chapter": "", + "previous chapter": "", + "quick access to all modules": "", + "search": "", + "search this documentation": "", + "the documentation for": "" + }, + "plural_expr": "(n != 1)" +});
\ No newline at end of file diff --git a/sphinx/locale/ur/LC_MESSAGES/sphinx.po b/sphinx/locale/ur/LC_MESSAGES/sphinx.po index c674b9283..c37314be1 100644 --- a/sphinx/locale/ur/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ur/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: msgid "" msgstr "" diff --git a/sphinx/locale/vi/LC_MESSAGES/sphinx.js b/sphinx/locale/vi/LC_MESSAGES/sphinx.js index 6fc9de980..36d619f9f 100644 --- a/sphinx/locale/vi/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/vi/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "vi", "messages": {"%(filename)s — %(docstitle)s": "", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", "© Copyright %(copyright)s.": "", ", in ": "", "About these documents": "V\u1ec1 c\u00e1c t\u00e0i li\u1ec7u n\u00e0y", "Automatically generated list of changes in version %(version)s": "", "C API changes": "", "Changes in Version %(version)s — %(docstitle)s": "", "Collapse sidebar": "", "Complete Table of Contents": "M\u1ee5c L\u1ee5c \u0110\u1ea7y \u0110\u1ee7", "Contents": "N\u1ed9i dung", "Copyright": "B\u1ea3n quy\u1ec1n", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u0110\u01b0\u1ee3c t\u1ea1o nh\u1edd <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", "Expand sidebar": "", "Full index on one page": "To\u00e0n b\u1ed9 ch\u1ec9 m\u1ee5c tr\u00ean m\u1ed9t trang", "General Index": "Ch\u1ec9 m\u1ee5c chung", "Global Module Index": "Ch\u1ec9 M\u1ee5c M\u00f4-\u0111un To\u00e0n C\u1ee5c", "Go": "Th\u1ef1c hi\u1ec7n", "Hide Search Matches": "", "Index": "", "Index – %(key)s": "Ch\u1ec9 m\u1ee5c – %(key)s", "Index pages by letter": "C\u00e1c trang ch\u1ec9 m\u1ee5c theo ch\u1eef c\u00e1i", "Indices and tables:": "C\u00e1c ch\u1ec9 m\u1ee5c v\u00e0 b\u1ea3ng bi\u1ec3u:", "Last updated on %(last_updated)s.": "C\u1eadp nh\u1eadt m\u1edbi nh\u1ea5t v\u00e0o %(last_updated)s.", "Library changes": "", "Navigation": "\u0110i\u1ec1u h\u01b0\u1edbng", "Next topic": "Ch\u1ee7 \u0111\u1ec1 ti\u1ebfp", "Other changes": "", "Overview": "T\u1ed5ng quan", "Permalink to this definition": "", "Permalink to this headline": "", "Please activate JavaScript to enable the search\n functionality.": "H\u00e3y b\u1eadt JavaScript \u0111\u1ec3 d\u00f9ng t\u00ednh n\u0103ng\nt\u00ecm ki\u1ebfm.", "Preparing search...": "", "Previous topic": "Ch\u1ee7 \u0111\u1ec1 tr\u01b0\u1edbc", "Quick search": "", "Search": "T\u00ecm Ki\u1ebfm", "Search Page": "", "Search Results": "", "Search finished, found %s page(s) matching the search query.": "", "Search within %(docstitle)s": "T\u00ecm ki\u1ebfm trong %(docstitle)s", "Searching": "", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "Hi\u1ec3n th\u1ecb m\u00e3 ngu\u1ed3n", "Table of Contents": "", "This Page": "", "Welcome! This is": "Ch\u00e0o m\u1eebng! \u0110\u00e2y l\u00e0", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", "all functions, classes, terms": "t\u1ea5t c\u1ea3 c\u00e1c h\u00e0m, l\u1edbp, thu\u1eadt ng\u1eef", "can be huge": "c\u00f3 th\u1ec3 r\u1ea5t nhi\u1ec1u", "last updated": "c\u1eadp nh\u1eadt m\u1edbi nh\u1ea5t", "lists all sections and subsections": "li\u1ec7t k\u00ea t\u1ea5t c\u1ea3 c\u00e1c m\u1ee5c v\u00e0 m\u1ee5c con", "next chapter": "ch\u01b0\u01a1ng ti\u1ebfp", "previous chapter": "ch\u01b0\u01a1ng tr\u01b0\u1edbc ", "quick access to all modules": "truy c\u1eadp nhanh t\u1ea5t c\u1ea3 c\u00e1c m\u00f4-\u0111un", "search": "", "search this documentation": "t\u00ecm ki\u1ebfm trong t\u00e0i li\u1ec7u n\u00e0y", "the documentation for": "t\u00e0i li\u1ec7u cho"}, "plural_expr": "0"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "vi", + "messages": { + "%(filename)s — %(docstitle)s": "", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "", + "© Copyright %(copyright)s.": "", + ", in ": "", + "About these documents": "V\u1ec1 c\u00e1c t\u00e0i li\u1ec7u n\u00e0y", + "Automatically generated list of changes in version %(version)s": "", + "C API changes": "", + "Changes in Version %(version)s — %(docstitle)s": "", + "Collapse sidebar": "", + "Complete Table of Contents": "M\u1ee5c L\u1ee5c \u0110\u1ea7y \u0110\u1ee7", + "Contents": "N\u1ed9i dung", + "Copyright": "B\u1ea3n quy\u1ec1n", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u0110\u01b0\u1ee3c t\u1ea1o nh\u1edd <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.", + "Expand sidebar": "", + "Full index on one page": "To\u00e0n b\u1ed9 ch\u1ec9 m\u1ee5c tr\u00ean m\u1ed9t trang", + "General Index": "Ch\u1ec9 m\u1ee5c chung", + "Global Module Index": "Ch\u1ec9 M\u1ee5c M\u00f4-\u0111un To\u00e0n C\u1ee5c", + "Go": "Th\u1ef1c hi\u1ec7n", + "Hide Search Matches": "", + "Index": "", + "Index – %(key)s": "Ch\u1ec9 m\u1ee5c – %(key)s", + "Index pages by letter": "C\u00e1c trang ch\u1ec9 m\u1ee5c theo ch\u1eef c\u00e1i", + "Indices and tables:": "C\u00e1c ch\u1ec9 m\u1ee5c v\u00e0 b\u1ea3ng bi\u1ec3u:", + "Last updated on %(last_updated)s.": "C\u1eadp nh\u1eadt m\u1edbi nh\u1ea5t v\u00e0o %(last_updated)s.", + "Library changes": "", + "Navigation": "\u0110i\u1ec1u h\u01b0\u1edbng", + "Next topic": "Ch\u1ee7 \u0111\u1ec1 ti\u1ebfp", + "Other changes": "", + "Overview": "T\u1ed5ng quan", + "Permalink to this definition": "", + "Permalink to this headline": "", + "Please activate JavaScript to enable the search\n functionality.": "H\u00e3y b\u1eadt JavaScript \u0111\u1ec3 d\u00f9ng t\u00ednh n\u0103ng\nt\u00ecm ki\u1ebfm.", + "Preparing search...": "", + "Previous topic": "Ch\u1ee7 \u0111\u1ec1 tr\u01b0\u1edbc", + "Quick search": "", + "Search": "T\u00ecm Ki\u1ebfm", + "Search Page": "", + "Search Results": "", + "Search finished, found %s page(s) matching the search query.": "", + "Search within %(docstitle)s": "T\u00ecm ki\u1ebfm trong %(docstitle)s", + "Searching": "", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "Hi\u1ec3n th\u1ecb m\u00e3 ngu\u1ed3n", + "Table of Contents": "", + "This Page": "", + "Welcome! This is": "Ch\u00e0o m\u1eebng! \u0110\u00e2y l\u00e0", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "", + "all functions, classes, terms": "t\u1ea5t c\u1ea3 c\u00e1c h\u00e0m, l\u1edbp, thu\u1eadt ng\u1eef", + "can be huge": "c\u00f3 th\u1ec3 r\u1ea5t nhi\u1ec1u", + "last updated": "c\u1eadp nh\u1eadt m\u1edbi nh\u1ea5t", + "lists all sections and subsections": "li\u1ec7t k\u00ea t\u1ea5t c\u1ea3 c\u00e1c m\u1ee5c v\u00e0 m\u1ee5c con", + "next chapter": "ch\u01b0\u01a1ng ti\u1ebfp", + "previous chapter": "ch\u01b0\u01a1ng tr\u01b0\u1edbc ", + "quick access to all modules": "truy c\u1eadp nhanh t\u1ea5t c\u1ea3 c\u00e1c m\u00f4-\u0111un", + "search": "", + "search this documentation": "t\u00ecm ki\u1ebfm trong t\u00e0i li\u1ec7u n\u00e0y", + "the documentation for": "t\u00e0i li\u1ec7u cho" + }, + "plural_expr": "0" +});
\ No newline at end of file diff --git a/sphinx/locale/vi/LC_MESSAGES/sphinx.po b/sphinx/locale/vi/LC_MESSAGES/sphinx.po index 83b579ea4..20c77edeb 100644 --- a/sphinx/locale/vi/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/vi/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Hoat Le Van <hoatlevan@gmail.com>, 2014 msgid "" diff --git a/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.js b/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.js index d5973ca66..ac4359e6f 100644 --- a/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "zh_Hans_CN", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\"> \u7248\u6743\u6240\u6709</a> %(copyright)s.", "© Copyright %(copyright)s.": "© \u7248\u6743\u6240\u6709 %(copyright)s.", ", in ": "\uff0c \u5728 ", "About these documents": "\u5173\u4e8e\u8fd9\u4e9b\u6587\u6863", "Automatically generated list of changes in version %(version)s": "\u81ea\u52a8\u751f\u6210\u7684 %(version)s \u7248\u672c\u4e2d\u7684\u66f4\u6539\u5217\u8868", "C API changes": "C API \u66f4\u6539", "Changes in Version %(version)s — %(docstitle)s": "\u66f4\u6539\u53d1\u751f\u5728\u7248\u672c %(version)s— %(docstitle)s", "Collapse sidebar": "\u6298\u53e0\u8fb9\u680f", "Complete Table of Contents": "\u5b8c\u6574\u7684\u5185\u5bb9\u8868", "Contents": "\u76ee\u5f55", "Copyright": "\u7248\u6743\u6240\u6709", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u7531 <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u521b\u5efa\u3002", "Expand sidebar": "\u5c55\u5f00\u8fb9\u680f", "Full index on one page": "\u4e00\u9875\u7684\u5168\u90e8\u7d22\u5f15", "General Index": "\u603b\u76ee\u5f55", "Global Module Index": "\u5168\u5c40\u6a21\u5757\u7d22\u5f15", "Go": "\u8f6c\u5411", "Hide Search Matches": "\u9690\u85cf\u641c\u7d22\u7ed3\u679c", "Index": "\u7d22\u5f15", "Index – %(key)s": "\u7d22\u5f15 – %(key)s", "Index pages by letter": "\u6309\u7167\u5b57\u6bcd\u7684\u7d22\u5f15\u9875", "Indices and tables:": "\u7d22\u5f15\u548c\u8868\u683c\uff1a", "Last updated on %(last_updated)s.": "\u6700\u540e\u66f4\u65b0\u4e8e %(last_updated)s.", "Library changes": "\u5e93\u66f4\u6539", "Navigation": "\u5bfc\u822a", "Next topic": "\u4e0b\u4e00\u4e2a\u4e3b\u9898", "Other changes": "\u5176\u4ed6\u66f4\u6539", "Overview": "\u6982\u8ff0", "Permalink to this definition": "\u6c38\u4e45\u94fe\u63a5\u81f3\u76ee\u6807", "Permalink to this headline": "\u6c38\u4e45\u94fe\u63a5\u81f3\u6807\u9898", "Please activate JavaScript to enable the search\n functionality.": "\u8bf7\u6fc0\u6d3b JavaScript \u4ee5\u5f00\u542f\u641c\u7d22\u529f\u80fd\u3002", "Preparing search...": "\u51c6\u5907\u641c\u7d22\u2026\u2026", "Previous topic": "\u4e0a\u4e00\u4e2a\u4e3b\u9898", "Quick search": "\u5feb\u901f\u641c\u7d22", "Search": "\u641c\u7d22", "Search Page": "\u641c\u7d22\u9875\u9762", "Search Results": "\u641c\u7d22\u7ed3\u679c", "Search finished, found %s page(s) matching the search query.": "\u641c\u7d22\u5b8c\u6210\uff0c\u6709 %s \u4e2a\u9875\u9762\u5339\u914d\u3002", "Search within %(docstitle)s": "\u5728 %(docstitle)s \u4e2d\u641c\u7d22", "Searching": "\u641c\u7d22\u4e2d", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u663e\u793a\u6e90\u4ee3\u7801", "Table of Contents": "\u76ee\u5f55", "This Page": "\u672c\u9875", "Welcome! This is": "\u6b22\u8fce\uff01\u8fd9\u662f", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u6ca1\u6709\u4efb\u4f55\u6587\u6863\u5339\u914d\u60a8\u7684\u641c\u7d22\u3002\u8bf7\u786e\u4fdd\u4f60\u8f93\u5165\u7684\u8bcd\u62fc\u5199\u6b63\u786e\u5e76\u9009\u62e9\u4e86\u5408\u9002\u7684\u5206\u7c7b\u3002", "all functions, classes, terms": "\u6240\u7684\u51fd\u6570\uff0c\u7c7b\uff0c\u672f\u8bed", "can be huge": "\u53ef\u80fd\u4f1a\u5f88\u591a", "last updated": "\u6700\u540e\u66f4\u65b0\u4e8e", "lists all sections and subsections": "\u5217\u51fa\u6240\u6709\u7684\u7ae0\u8282\u548c\u90e8\u5206", "next chapter": "\u4e0b\u4e00\u7ae0", "previous chapter": "\u4e0a\u4e00\u7ae0", "quick access to all modules": "\u5feb\u901f\u67e5\u770b\u6240\u6709\u7684\u6a21\u5757", "search": "\u641c\u7d22", "search this documentation": "\u641c\u7d22\u6587\u6863", "the documentation for": "\u8fd9\u4efd\u6587\u6863\u662f"}, "plural_expr": "0"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "zh_Hans_CN", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\"> \u7248\u6743\u6240\u6709</a> %(copyright)s.", + "© Copyright %(copyright)s.": "© \u7248\u6743\u6240\u6709 %(copyright)s.", + ", in ": "\uff0c \u5728 ", + "About these documents": "\u5173\u4e8e\u8fd9\u4e9b\u6587\u6863", + "Automatically generated list of changes in version %(version)s": "\u81ea\u52a8\u751f\u6210\u7684 %(version)s \u7248\u672c\u4e2d\u7684\u66f4\u6539\u5217\u8868", + "C API changes": "C API \u66f4\u6539", + "Changes in Version %(version)s — %(docstitle)s": "\u66f4\u6539\u53d1\u751f\u5728\u7248\u672c %(version)s— %(docstitle)s", + "Collapse sidebar": "\u6298\u53e0\u8fb9\u680f", + "Complete Table of Contents": "\u5b8c\u6574\u7684\u5185\u5bb9\u8868", + "Contents": "\u76ee\u5f55", + "Copyright": "\u7248\u6743\u6240\u6709", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u7531 <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u521b\u5efa\u3002", + "Expand sidebar": "\u5c55\u5f00\u8fb9\u680f", + "Full index on one page": "\u4e00\u9875\u7684\u5168\u90e8\u7d22\u5f15", + "General Index": "\u603b\u76ee\u5f55", + "Global Module Index": "\u5168\u5c40\u6a21\u5757\u7d22\u5f15", + "Go": "\u8f6c\u5411", + "Hide Search Matches": "\u9690\u85cf\u641c\u7d22\u7ed3\u679c", + "Index": "\u7d22\u5f15", + "Index – %(key)s": "\u7d22\u5f15 – %(key)s", + "Index pages by letter": "\u6309\u7167\u5b57\u6bcd\u7684\u7d22\u5f15\u9875", + "Indices and tables:": "\u7d22\u5f15\u548c\u8868\u683c\uff1a", + "Last updated on %(last_updated)s.": "\u6700\u540e\u66f4\u65b0\u4e8e %(last_updated)s.", + "Library changes": "\u5e93\u66f4\u6539", + "Navigation": "\u5bfc\u822a", + "Next topic": "\u4e0b\u4e00\u4e2a\u4e3b\u9898", + "Other changes": "\u5176\u4ed6\u66f4\u6539", + "Overview": "\u6982\u8ff0", + "Permalink to this definition": "\u6c38\u4e45\u94fe\u63a5\u81f3\u76ee\u6807", + "Permalink to this headline": "\u6c38\u4e45\u94fe\u63a5\u81f3\u6807\u9898", + "Please activate JavaScript to enable the search\n functionality.": "\u8bf7\u6fc0\u6d3b JavaScript \u4ee5\u5f00\u542f\u641c\u7d22\u529f\u80fd\u3002", + "Preparing search...": "\u51c6\u5907\u641c\u7d22\u2026\u2026", + "Previous topic": "\u4e0a\u4e00\u4e2a\u4e3b\u9898", + "Quick search": "\u5feb\u901f\u641c\u7d22", + "Search": "\u641c\u7d22", + "Search Page": "\u641c\u7d22\u9875\u9762", + "Search Results": "\u641c\u7d22\u7ed3\u679c", + "Search finished, found %s page(s) matching the search query.": "\u641c\u7d22\u5b8c\u6210\uff0c\u6709 %s \u4e2a\u9875\u9762\u5339\u914d\u3002", + "Search within %(docstitle)s": "\u5728 %(docstitle)s \u4e2d\u641c\u7d22", + "Searching": "\u641c\u7d22\u4e2d", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u663e\u793a\u6e90\u4ee3\u7801", + "Table of Contents": "\u76ee\u5f55", + "This Page": "\u672c\u9875", + "Welcome! This is": "\u6b22\u8fce\uff01\u8fd9\u662f", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u6ca1\u6709\u4efb\u4f55\u6587\u6863\u5339\u914d\u60a8\u7684\u641c\u7d22\u3002\u8bf7\u786e\u4fdd\u4f60\u8f93\u5165\u7684\u8bcd\u62fc\u5199\u6b63\u786e\u5e76\u9009\u62e9\u4e86\u5408\u9002\u7684\u5206\u7c7b\u3002", + "all functions, classes, terms": "\u6240\u7684\u51fd\u6570\uff0c\u7c7b\uff0c\u672f\u8bed", + "can be huge": "\u53ef\u80fd\u4f1a\u5f88\u591a", + "last updated": "\u6700\u540e\u66f4\u65b0\u4e8e", + "lists all sections and subsections": "\u5217\u51fa\u6240\u6709\u7684\u7ae0\u8282\u548c\u90e8\u5206", + "next chapter": "\u4e0b\u4e00\u7ae0", + "previous chapter": "\u4e0a\u4e00\u7ae0", + "quick access to all modules": "\u5feb\u901f\u67e5\u770b\u6240\u6709\u7684\u6a21\u5757", + "search": "\u641c\u7d22", + "search this documentation": "\u641c\u7d22\u6587\u6863", + "the documentation for": "\u8fd9\u4efd\u6587\u6863\u662f" + }, + "plural_expr": "0" +});
\ No newline at end of file diff --git a/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po b/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po index 47cb76210..5b9491c53 100644 --- a/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Yinian Chin <yinian1992@live.com>, 2015,2017-2018 # Hsiaoming Yang <me@lepture.com>, 2018 diff --git a/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js b/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js index 1a339824f..0b0ce240a 100644 --- a/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js @@ -1 +1,63 @@ -Documentation.addTranslations({"locale": "zh_Hant_TW", "messages": {"%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">\u7248\u6b0a\u6240\u6709</a> %(copyright)s\u3002", "© Copyright %(copyright)s.": "© \u7248\u6b0a\u6240\u6709 %(copyright)s\u3002", ", in ": " \u65bc ", "About these documents": "\u95dc\u65bc\u9019\u4e9b\u6587\u4ef6", "Automatically generated list of changes in version %(version)s": "\u81ea\u52d5\u7522\u751f\u7684 %(version)s \u7248\u672c\u6539\u8b8a\u5217\u8868", "C API changes": "C API \u6539\u8b8a", "Changes in Version %(version)s — %(docstitle)s": "\u65bc %(version)s \u7248\u672c\u4e2d\u7684\u6240\u6709\u66f4\u8b8a — %(docstitle)s", "Collapse sidebar": "\u6536\u5408\u5074\u908a\u6b04", "Complete Table of Contents": "\u5b8c\u6574\u76ee\u9304", "Contents": "\u5167\u5bb9", "Copyright": "\u7248\u6b0a\u6240\u6709", "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u4f7f\u7528 <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u5275\u5efa\u3002", "Expand sidebar": "\u5c55\u958b\u5074\u908a\u6b04", "Full index on one page": "\u55ae\u9801\u5b8c\u6574\u7d22\u5f15", "General Index": "\u7e3d\u7d22\u5f15", "Global Module Index": "\u5168\u57df\u6a21\u7d44\u7d22\u5f15", "Go": "\u641c", "Hide Search Matches": "\u96b1\u85cf\u7b26\u5408\u641c\u5c0b", "Index": "\u7d22\u5f15", "Index – %(key)s": "\u7d22\u5f15 – %(key)s", "Index pages by letter": "\u7d22\u5f15\u9801\u9762\u6309\u5b57\u6bcd", "Indices and tables:": "\u7d22\u5f15\u8207\u8868\u683c\uff1a", "Last updated on %(last_updated)s.": "\u6700\u5f8c\u66f4\u65b0\u65bc %(last_updated)s\u3002", "Library changes": "\u7a0b\u5f0f\u5eab\u7684\u6539\u8b8a", "Navigation": "\u700f\u89bd", "Next topic": "\u4e0b\u500b\u4e3b\u984c", "Other changes": "\u5176\u4ed6\u6539\u8b8a", "Overview": "\u6982\u8981", "Permalink to this definition": "\u672c\u5b9a\u7fa9\u7684\u6c38\u4e45\u9023\u7d50", "Permalink to this headline": "\u672c\u6a19\u984c\u7684\u6c38\u4e45\u9023\u7d50", "Please activate JavaScript to enable the search\n functionality.": "\u8acb\u555f\u7528 Javascript \u4ee5\u958b\u555f\u641c\u5c0b\u529f\u80fd\u3002", "Preparing search...": "\u6e96\u5099\u641c\u5c0b\u4e2d\u2026", "Previous topic": "\u4e0a\u500b\u4e3b\u984c", "Quick search": "\u5feb\u901f\u641c\u5c0b", "Search": "\u641c\u5c0b", "Search Page": "\u641c\u5c0b\u9801\u9762", "Search Results": "\u641c\u5c0b\u7d50\u679c", "Search finished, found %s page(s) matching the search query.": "\u641c\u5c0b\u5b8c\u6210\uff0c\u5171\u627e\u5230 %s \u9801\u9762\u6eff\u8db3\u641c\u5c0b\u689d\u4ef6\u3002", "Search within %(docstitle)s": "\u5728 %(docstitle)s \u4e2d\u641c\u5c0b", "Searching": "\u641c\u5c0b\u4e2d", "Searching for multiple words only shows matches that contain\n all words.": "", "Show Source": "\u986f\u793a\u539f\u59cb\u78bc", "Table of Contents": "", "This Page": "\u672c\u9801", "Welcome! This is": "\u6b61\u8fce\uff01\u672c", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u4f60\u7684\u641c\u5c0b\u627e\u4e0d\u5230\u4efb\u4f55\u6eff\u8db3\u689d\u4ef6\u7684\u6587\u4ef6\u3002\u8acb\u78ba\u5b9a\u662f\u5426\u6240\u6709\u7684\u641c\u5c0b\u8a5e\u90fd\u6b63\u78ba\u5730\u62fc\u5beb\u4e14\u4f60\u5df2\u9078\u64c7\u8db3\u5920\u7684\u5206\u985e\u3002", "all functions, classes, terms": "\u6240\u6709\u51fd\u5f0f\u3001\u985e\u5225\u3001\u8853\u8a9e", "can be huge": "\u53ef\u80fd\u6703\u5f88\u5927", "last updated": "\u6700\u5f8c\u66f4\u65b0\u65bc", "lists all sections and subsections": "\u5217\u51fa\u6240\u6709\u6bb5\u843d\u8207\u5b50\u6bb5\u843d", "next chapter": "\u4e0b\u4e00\u7ae0", "previous chapter": "\u4e0a\u4e00\u7ae0", "quick access to all modules": "\u5feb\u901f\u524d\u5f80\u6240\u6709\u7684\u6a21\u7d44", "search": "\u641c\u5c0b", "search this documentation": "\u641c\u5c0b\u672c\u8aaa\u660e\u6587\u4ef6", "the documentation for": "\u8aaa\u660e\u6587\u4ef6\u4ecb\u7d39"}, "plural_expr": "0"});
\ No newline at end of file +Documentation.addTranslations({ + "locale": "zh_Hant_TW", + "messages": { + "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s", + "© <a href=\"%(path)s\">Copyright</a> %(copyright)s.": "© <a href=\"%(path)s\">\u7248\u6b0a\u6240\u6709</a> %(copyright)s\u3002", + "© Copyright %(copyright)s.": "© \u7248\u6b0a\u6240\u6709 %(copyright)s\u3002", + ", in ": " \u65bc ", + "About these documents": "\u95dc\u65bc\u9019\u4e9b\u6587\u4ef6", + "Automatically generated list of changes in version %(version)s": "\u81ea\u52d5\u7522\u751f\u7684 %(version)s \u7248\u672c\u6539\u8b8a\u5217\u8868", + "C API changes": "C API \u6539\u8b8a", + "Changes in Version %(version)s — %(docstitle)s": "\u65bc %(version)s \u7248\u672c\u4e2d\u7684\u6240\u6709\u66f4\u8b8a — %(docstitle)s", + "Collapse sidebar": "\u6536\u5408\u5074\u908a\u6b04", + "Complete Table of Contents": "\u5b8c\u6574\u76ee\u9304", + "Contents": "\u5167\u5bb9", + "Copyright": "\u7248\u6b0a\u6240\u6709", + "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s.": "\u4f7f\u7528 <a href=\"http://sphinx-doc.org/\">Sphinx</a> %(sphinx_version)s \u5275\u5efa\u3002", + "Expand sidebar": "\u5c55\u958b\u5074\u908a\u6b04", + "Full index on one page": "\u55ae\u9801\u5b8c\u6574\u7d22\u5f15", + "General Index": "\u7e3d\u7d22\u5f15", + "Global Module Index": "\u5168\u57df\u6a21\u7d44\u7d22\u5f15", + "Go": "\u641c", + "Hide Search Matches": "\u96b1\u85cf\u7b26\u5408\u641c\u5c0b", + "Index": "\u7d22\u5f15", + "Index – %(key)s": "\u7d22\u5f15 – %(key)s", + "Index pages by letter": "\u7d22\u5f15\u9801\u9762\u6309\u5b57\u6bcd", + "Indices and tables:": "\u7d22\u5f15\u8207\u8868\u683c\uff1a", + "Last updated on %(last_updated)s.": "\u6700\u5f8c\u66f4\u65b0\u65bc %(last_updated)s\u3002", + "Library changes": "\u7a0b\u5f0f\u5eab\u7684\u6539\u8b8a", + "Navigation": "\u700f\u89bd", + "Next topic": "\u4e0b\u500b\u4e3b\u984c", + "Other changes": "\u5176\u4ed6\u6539\u8b8a", + "Overview": "\u6982\u8981", + "Permalink to this definition": "\u672c\u5b9a\u7fa9\u7684\u6c38\u4e45\u9023\u7d50", + "Permalink to this headline": "\u672c\u6a19\u984c\u7684\u6c38\u4e45\u9023\u7d50", + "Please activate JavaScript to enable the search\n functionality.": "\u8acb\u555f\u7528 Javascript \u4ee5\u958b\u555f\u641c\u5c0b\u529f\u80fd\u3002", + "Preparing search...": "\u6e96\u5099\u641c\u5c0b\u4e2d\u2026", + "Previous topic": "\u4e0a\u500b\u4e3b\u984c", + "Quick search": "\u5feb\u901f\u641c\u5c0b", + "Search": "\u641c\u5c0b", + "Search Page": "\u641c\u5c0b\u9801\u9762", + "Search Results": "\u641c\u5c0b\u7d50\u679c", + "Search finished, found %s page(s) matching the search query.": "\u641c\u5c0b\u5b8c\u6210\uff0c\u5171\u627e\u5230 %s \u9801\u9762\u6eff\u8db3\u641c\u5c0b\u689d\u4ef6\u3002", + "Search within %(docstitle)s": "\u5728 %(docstitle)s \u4e2d\u641c\u5c0b", + "Searching": "\u641c\u5c0b\u4e2d", + "Searching for multiple words only shows matches that contain\n all words.": "", + "Show Source": "\u986f\u793a\u539f\u59cb\u78bc", + "Table of Contents": "", + "This Page": "\u672c\u9801", + "Welcome! This is": "\u6b61\u8fce\uff01\u672c", + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u4f60\u7684\u641c\u5c0b\u627e\u4e0d\u5230\u4efb\u4f55\u6eff\u8db3\u689d\u4ef6\u7684\u6587\u4ef6\u3002\u8acb\u78ba\u5b9a\u662f\u5426\u6240\u6709\u7684\u641c\u5c0b\u8a5e\u90fd\u6b63\u78ba\u5730\u62fc\u5beb\u4e14\u4f60\u5df2\u9078\u64c7\u8db3\u5920\u7684\u5206\u985e\u3002", + "all functions, classes, terms": "\u6240\u6709\u51fd\u5f0f\u3001\u985e\u5225\u3001\u8853\u8a9e", + "can be huge": "\u53ef\u80fd\u6703\u5f88\u5927", + "last updated": "\u6700\u5f8c\u66f4\u65b0\u65bc", + "lists all sections and subsections": "\u5217\u51fa\u6240\u6709\u6bb5\u843d\u8207\u5b50\u6bb5\u843d", + "next chapter": "\u4e0b\u4e00\u7ae0", + "previous chapter": "\u4e0a\u4e00\u7ae0", + "quick access to all modules": "\u5feb\u901f\u524d\u5f80\u6240\u6709\u7684\u6a21\u7d44", + "search": "\u641c\u5c0b", + "search this documentation": "\u641c\u5c0b\u672c\u8aaa\u660e\u6587\u4ef6", + "the documentation for": "\u8aaa\u660e\u6587\u4ef6\u4ecb\u7d39" + }, + "plural_expr": "0" +});
\ No newline at end of file diff --git a/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po b/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po index 67b4d2b81..435fe0453 100644 --- a/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po @@ -1,7 +1,7 @@ # Translations template for Sphinx. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# +# # Translators: # Adrian Liaw <adrianliaw2000@gmail.com>, 2018 # Fred Lin <gasolin@gmail.com>, 2008 diff --git a/sphinx/parsers.py b/sphinx/parsers.py index 6a07d1801..17c291af7 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -4,7 +4,7 @@ A Base class for additional parsers. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -23,8 +23,10 @@ from sphinx.util.rst import append_epilog, prepend_prolog if False: # For type annotation - from docutils.transforms import Transform # NOQA from typing import Type # NOQA # for python3.5.1 + + from docutils.transforms import Transform # NOQA + from sphinx.application import Sphinx diff --git a/sphinx/project.py b/sphinx/project.py index f4afdadad..e5df4013f 100644 --- a/sphinx/project.py +++ b/sphinx/project.py @@ -4,7 +4,7 @@ Utility function and classes for Sphinx projects. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,9 +12,7 @@ import os from glob import glob from sphinx.locale import __ -from sphinx.util import get_matching_files -from sphinx.util import logging -from sphinx.util import path_stabilize +from sphinx.util import get_matching_files, logging, path_stabilize from sphinx.util.matching import compile_matchers from sphinx.util.osutil import SEP, relpath diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index 4879fb349..ab0dfdbf8 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -4,20 +4,22 @@ Utilities parsing and analyzing Python code. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re import tokenize import warnings +from collections import OrderedDict from importlib import import_module +from inspect import Signature from io import StringIO from os import path -from typing import Any, Dict, IO, List, Tuple, Optional +from typing import IO, Any, Dict, List, Optional, Tuple from zipfile import ZipFile -from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.errors import PycodeError from sphinx.pycode.parser import Parser @@ -36,7 +38,7 @@ class ModuleAnalyzer: try: mod = import_module(modname) except Exception as err: - raise PycodeError('error importing %r' % modname, err) + raise PycodeError('error importing %r' % modname, err) from err loader = getattr(mod, '__loader__', None) filename = getattr(mod, '__file__', None) if loader and getattr(loader, 'get_source', None): @@ -53,7 +55,7 @@ class ModuleAnalyzer: try: filename = loader.get_filename(modname) except ImportError as err: - raise PycodeError('error getting filename for %r' % modname, err) + raise PycodeError('error getting filename for %r' % modname, err) from err if filename is None: # all methods for getting filename failed, so raise... raise PycodeError('no source found for module %r' % modname) @@ -91,7 +93,7 @@ class ModuleAnalyzer: if '.egg' + path.sep in filename: obj = cls.cache['file', filename] = cls.for_egg(filename, modname) else: - raise PycodeError('error opening %r' % filename, err) + raise PycodeError('error opening %r' % filename, err) from err return obj @classmethod @@ -103,7 +105,7 @@ class ModuleAnalyzer: code = egg.read(relpath).decode() return cls.for_string(code, modname, filename) except Exception as exc: - raise PycodeError('error opening %r' % filename, exc) + raise PycodeError('error opening %r' % filename, exc) from exc @classmethod def for_module(cls, modname: str) -> "ModuleAnalyzer": @@ -141,20 +143,31 @@ class ModuleAnalyzer: self._encoding = None self.code = source.read() - # will be filled by parse() + # will be filled by analyze() self.annotations = None # type: Dict[Tuple[str, str], str] self.attr_docs = None # type: Dict[Tuple[str, str], List[str]] self.finals = None # type: List[str] + self.overloads = None # type: Dict[str, List[Signature]] self.tagorder = None # type: Dict[str, int] self.tags = None # type: Dict[str, Tuple[str, int, int]] + self._analyzed = False def parse(self) -> None: """Parse the source code.""" + warnings.warn('ModuleAnalyzer.parse() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + self.analyze() + + def analyze(self) -> None: + """Analyze the source code.""" + if self._analyzed: + return None + try: parser = Parser(self.code, self._encoding) parser.parse() - self.attr_docs = {} + self.attr_docs = OrderedDict() for (scope, comment) in parser.comments.items(): if comment: self.attr_docs[scope] = comment.splitlines() + [''] @@ -163,23 +176,21 @@ class ModuleAnalyzer: self.annotations = parser.annotations self.finals = parser.finals + self.overloads = parser.overloads self.tags = parser.definitions self.tagorder = parser.deforders + self._analyzed = True except Exception as exc: - raise PycodeError('parsing %r failed: %r' % (self.srcname, exc)) + raise PycodeError('parsing %r failed: %r' % (self.srcname, exc)) from exc def find_attr_docs(self) -> Dict[Tuple[str, str], List[str]]: """Find class and module-level attributes and their documentation.""" - if self.attr_docs is None: - self.parse() - + self.analyze() return self.attr_docs def find_tags(self) -> Dict[str, Tuple[str, int, int]]: """Find class, function and method definitions and their location.""" - if self.tags is None: - self.parse() - + self.analyze() return self.tags @property diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index 9bafff11c..65534f958 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -4,12 +4,12 @@ Helpers for AST (Abstract Syntax Tree). - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import sys -from typing import Dict, List, Type, Optional +from typing import Dict, List, Optional, Type if sys.version_info > (3, 8): import ast @@ -52,23 +52,29 @@ def parse(code: str, mode: str = 'exec') -> "ast.AST": try: # type_comments parameter is available on py38+ return ast.parse(code, mode=mode, type_comments=True) # type: ignore + except SyntaxError: + # Some syntax error found. To ignore invalid type comments, retry parsing without + # type_comments parameter (refs: https://github.com/sphinx-doc/sphinx/issues/8652). + return ast.parse(code, mode=mode) except TypeError: # fallback to ast module. # typed_ast is used to parse type_comments if installed. return ast.parse(code, mode=mode) -def unparse(node: Optional[ast.AST]) -> Optional[str]: +def unparse(node: Optional[ast.AST], code: str = '') -> Optional[str]: """Unparse an AST to string.""" if node is None: return None elif isinstance(node, str): return node - return _UnparseVisitor().visit(node) + return _UnparseVisitor(code).visit(node) # a greatly cut-down version of `ast._Unparser` class _UnparseVisitor(ast.NodeVisitor): + def __init__(self, code: str = '') -> None: + self.code = code def _visit_op(self, node: ast.AST) -> str: return OPERATORS[node.__class__] @@ -166,14 +172,28 @@ class _UnparseVisitor(ast.NodeVisitor): return "{" + ", ".join(self.visit(e) for e in node.elts) + "}" def visit_Subscript(self, node: ast.Subscript) -> str: - return "%s[%s]" % (self.visit(node.value), self.visit(node.slice)) + def is_simple_tuple(value: ast.AST) -> bool: + return ( + isinstance(value, ast.Tuple) and + bool(value.elts) and + not any(isinstance(elt, ast.Starred) for elt in value.elts) + ) + + if is_simple_tuple(node.slice): + elts = ", ".join(self.visit(e) for e in node.slice.elts) # type: ignore + return "%s[%s]" % (self.visit(node.value), elts) + elif isinstance(node.slice, ast.Index) and is_simple_tuple(node.slice.value): + elts = ", ".join(self.visit(e) for e in node.slice.value.elts) # type: ignore + return "%s[%s]" % (self.visit(node.value), elts) + else: + return "%s[%s]" % (self.visit(node.value), self.visit(node.slice)) def visit_UnaryOp(self, node: ast.UnaryOp) -> str: return "%s %s" % (self.visit(node.op), self.visit(node.operand)) def visit_Tuple(self, node: ast.Tuple) -> str: if node.elts: - return ", ".join(self.visit(e) for e in node.elts) + return "(" + ", ".join(self.visit(e) for e in node.elts) + ")" else: return "()" @@ -181,6 +201,11 @@ class _UnparseVisitor(ast.NodeVisitor): def visit_Constant(self, node: ast.Constant) -> str: if node.value is Ellipsis: return "..." + elif isinstance(node.value, (int, float, complex)): + if self.code and sys.version_info > (3, 8): + return ast.get_source_segment(self.code, node) + else: + return repr(node.value) else: return repr(node.value) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index 3762c72cc..dca59acd4 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -4,7 +4,7 @@ Utilities parsing and analyzing Python code. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import inspect @@ -12,14 +12,15 @@ import itertools import re import sys import tokenize -from token import NAME, NEWLINE, INDENT, DEDENT, NUMBER, OP, STRING +from collections import OrderedDict +from inspect import Signature +from token import DEDENT, INDENT, NAME, NEWLINE, NUMBER, OP, STRING from tokenize import COMMENT, NL from typing import Any, Dict, List, Optional, Tuple from sphinx.pycode.ast import ast # for py37 or older from sphinx.pycode.ast import parse, unparse - comment_re = re.compile('^\\s*#: ?(.*)\r?\n?$') indent_re = re.compile('^\\s*$') emptyline_re = re.compile('^\\s*(#.*)?$') @@ -227,13 +228,15 @@ class VariableCommentPicker(ast.NodeVisitor): self.context = [] # type: List[str] self.current_classes = [] # type: List[str] self.current_function = None # type: ast.FunctionDef - self.comments = {} # type: Dict[Tuple[str, str], str] + self.comments = OrderedDict() # type: Dict[Tuple[str, str], str] self.annotations = {} # type: Dict[Tuple[str, str], str] self.previous = None # type: ast.AST self.deforders = {} # type: Dict[str, int] self.finals = [] # type: List[str] + self.overloads = {} # type: Dict[str, List[Signature]] self.typing = None # type: str self.typing_final = None # type: str + self.typing_overload = None # type: str super().__init__() def get_qualname_for(self, name: str) -> Optional[List[str]]: @@ -257,6 +260,14 @@ class VariableCommentPicker(ast.NodeVisitor): if qualname: self.finals.append(".".join(qualname)) + def add_overload_entry(self, func: ast.FunctionDef) -> None: + # avoid circular import problem + from sphinx.util.inspect import signature_from_ast + qualname = self.get_qualname_for(func.name) + if qualname: + overloads = self.overloads.setdefault(".".join(qualname), []) + overloads.append(signature_from_ast(func)) + def add_variable_comment(self, name: str, comment: str) -> None: qualname = self.get_qualname_for(name) if qualname: @@ -285,6 +296,22 @@ class VariableCommentPicker(ast.NodeVisitor): return False + def is_overload(self, decorators: List[ast.expr]) -> bool: + overload = [] + if self.typing: + overload.append('%s.overload' % self.typing) + if self.typing_overload: + overload.append(self.typing_overload) + + for decorator in decorators: + try: + if unparse(decorator) in overload: + return True + except NotImplementedError: + pass + + return False + def get_self(self) -> ast.arg: """Returns the name of first argument if in function.""" if self.current_function and self.current_function.args.args: @@ -310,6 +337,8 @@ class VariableCommentPicker(ast.NodeVisitor): self.typing = name.asname or name.name elif name.name == 'typing.final': self.typing_final = name.asname or name.name + elif name.name == 'typing.overload': + self.typing_overload = name.asname or name.name def visit_ImportFrom(self, node: ast.ImportFrom) -> None: """Handles Import node and record it to definition orders.""" @@ -318,6 +347,8 @@ class VariableCommentPicker(ast.NodeVisitor): if node.module == 'typing' and name.name == 'final': self.typing_final = name.asname or name.name + elif node.module == 'typing' and name.name == 'overload': + self.typing_overload = name.asname or name.name def visit_Assign(self, node: ast.Assign) -> None: """Handles Assign node and pick up a variable comment.""" @@ -417,6 +448,8 @@ class VariableCommentPicker(ast.NodeVisitor): self.add_entry(node.name) # should be called before setting self.current_function if self.is_final(node.decorator_list): self.add_final_entry(node.name) + if self.is_overload(node.decorator_list): + self.add_overload_entry(node) self.context.append(node.name) self.current_function = node for child in node.body: @@ -518,6 +551,7 @@ class Parser: self.deforders = {} # type: Dict[str, int] self.definitions = {} # type: Dict[str, Tuple[str, int, int]] self.finals = [] # type: List[str] + self.overloads = {} # type: Dict[str, List[Signature]] def parse(self) -> None: """Parse the source code.""" @@ -533,6 +567,7 @@ class Parser: self.comments = picker.comments self.deforders = picker.deforders self.finals = picker.finals + self.overloads = picker.overloads def parse_definition(self) -> None: """Parse the location of definitions from the code.""" diff --git a/sphinx/pygments_styles.py b/sphinx/pygments_styles.py index c5b07e75f..1046826af 100644 --- a/sphinx/pygments_styles.py +++ b/sphinx/pygments_styles.py @@ -4,14 +4,14 @@ Sphinx theme specific highlighting styles. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from pygments.style import Style from pygments.styles.friendly import FriendlyStyle -from pygments.token import Generic, Comment, Number, Whitespace, Keyword, \ - Operator, Name, String, Error +from pygments.token import (Comment, Error, Generic, Keyword, Name, Number, Operator, String, + Whitespace) class NoneStyle(Style): diff --git a/sphinx/registry.py b/sphinx/registry.py index cad74559c..c6a249e74 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -4,7 +4,7 @@ Sphinx component registry. - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -38,6 +38,7 @@ from sphinx.util.typing import RoleFunction, TitleGetter if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx from sphinx.ext.autodoc import Documenter @@ -62,7 +63,7 @@ class SphinxComponentRegistry: self.documenters = {} # type: Dict[str, Type[Documenter]] #: css_files; a list of tuple of filename and attributes - self.css_files = [] # type: List[Tuple[str, Dict[str, str]]] + self.css_files = [] # type: List[Tuple[str, Dict[str, Any]]] #: domains; a dict of domain name -> domain class self.domains = {} # type: Dict[str, Type[Domain]] @@ -93,7 +94,7 @@ class SphinxComponentRegistry: self.html_block_math_renderers = {} # type: Dict[str, Tuple[Callable, Callable]] #: js_files; list of JS paths or URLs - self.js_files = [] # type: List[Tuple[str, Dict[str, str]]] + self.js_files = [] # type: List[Tuple[str, Dict[str, Any]]] #: LaTeX packages; list of package names and its options self.latex_packages = [] # type: List[Tuple[str, str]] @@ -139,9 +140,9 @@ class SphinxComponentRegistry: entry_points = iter_entry_points('sphinx.builders', name) try: entry_point = next(entry_points) - except StopIteration: + except StopIteration as exc: raise SphinxError(__('Builder name %s not registered or available' - ' through entry point') % name) + ' through entry point') % name) from exc self.load_extension(app, entry_point.module_name) @@ -259,12 +260,12 @@ class SphinxComponentRegistry: else: self.source_suffix[suffix] = filetype - def add_source_parser(self, parser: "Type[Parser]", **kwargs: Any) -> None: + def add_source_parser(self, parser: "Type[Parser]", override: bool = False) -> None: logger.debug('[app] adding search source_parser: %r', parser) # create a map from filetype to parser for filetype in parser.supported: - if filetype in self.source_parsers and not kwargs.get('override'): + if filetype in self.source_parsers and not override: raise ExtensionError(__('source_parser for %r is already registered') % filetype) else: @@ -273,8 +274,8 @@ class SphinxComponentRegistry: def get_source_parser(self, filetype: str) -> "Type[Parser]": try: return self.source_parsers[filetype] - except KeyError: - raise SphinxError(__('Source parser for %s not registered') % filetype) + except KeyError as exc: + raise SphinxError(__('Source parser for %s not registered') % filetype) from exc def get_source_parsers(self) -> Dict[str, "Type[Parser]"]: return self.source_parsers @@ -311,9 +312,11 @@ class SphinxComponentRegistry: try: visit, depart = handlers # unpack once for assertion translation_handlers[node.__name__] = (visit, depart) - except ValueError: - raise ExtensionError(__('kwargs for add_node() must be a (visit, depart) ' - 'function tuple: %r=%r') % (builder_name, handlers)) + except ValueError as exc: + raise ExtensionError( + __('kwargs for add_node() must be a (visit, depart) ' + 'function tuple: %r=%r') % (builder_name, handlers) + ) from exc def get_translator_class(self, builder: Builder) -> "Type[nodes.NodeVisitor]": return self.translators.get(builder.name, @@ -358,14 +361,21 @@ class SphinxComponentRegistry: attrgetter: Callable[[Any, str, Any], Any]) -> None: self.autodoc_attrgettrs[typ] = attrgetter - def add_css_files(self, filename: str, **attributes: str) -> None: + def add_css_files(self, filename: str, **attributes: Any) -> None: self.css_files.append((filename, attributes)) - def add_js_file(self, filename: str, **attributes: str) -> None: + def add_js_file(self, filename: str, **attributes: Any) -> None: logger.debug('[app] adding js_file: %r, %r', filename, attributes) self.js_files.append((filename, attributes)) + def has_latex_package(self, name: str) -> bool: + packages = self.latex_packages + self.latex_packages_after_hyperref + return bool([x for x in packages if x[0] == name]) + def add_latex_package(self, name: str, options: str, after_hyperref: bool = False) -> None: + if self.has_latex_package(name): + logger.warn("latex package '%s' already included" % name) + logger.debug('[app] adding latex package: %r', name) if after_hyperref: self.latex_packages_after_hyperref.append((name, options)) @@ -392,7 +402,7 @@ class SphinxComponentRegistry: def load_extension(self, app: "Sphinx", extname: str) -> None: """Load a Sphinx extension.""" - if extname in app.extensions: # alread loaded + if extname in app.extensions: # already loaded return if extname in EXTENSION_BLACKLIST: logger.warning(__('the extension %r was already merged with Sphinx since ' @@ -407,7 +417,8 @@ class SphinxComponentRegistry: mod = import_module(extname) except ImportError as err: logger.verbose(__('Original exception:\n') + traceback.format_exc()) - raise ExtensionError(__('Could not import extension %s') % extname, err) + raise ExtensionError(__('Could not import extension %s') % extname, + err) from err setup = getattr(mod, 'setup', None) if setup is None: @@ -423,7 +434,7 @@ class SphinxComponentRegistry: __('The %s extension used by this project needs at least ' 'Sphinx v%s; it therefore cannot be built with this ' 'version.') % (extname, err) - ) + ) from err if metadata is None: metadata = {} diff --git a/sphinx/roles.py b/sphinx/roles.py index 57d11c269..4f9261360 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -4,7 +4,7 @@ Handlers for additional ReST roles. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -21,14 +21,13 @@ from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.locale import _ from sphinx.util import ws_re from sphinx.util.docutils import ReferenceRole, SphinxRole -from sphinx.util.nodes import ( - split_explicit_title, process_index_entry, set_role_source_info -) +from sphinx.util.nodes import process_index_entry, set_role_source_info, split_explicit_title from sphinx.util.typing import RoleFunction if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment @@ -530,14 +529,15 @@ class Abbreviation(SphinxRole): abbr_re = re.compile(r'\((.*)\)$', re.S) def run(self) -> Tuple[List[Node], List[system_message]]: + options = self.options.copy() matched = self.abbr_re.search(self.text) if matched: text = self.text[:matched.start()].strip() - self.options['explanation'] = matched.group(1) + options['explanation'] = matched.group(1) else: text = self.text - return [nodes.abbreviation(self.rawtext, text, **self.options)], [] + return [nodes.abbreviation(self.rawtext, text, **options)], [] def index_role(typ: str, rawtext: str, text: str, lineno: int, inliner: Inliner, diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index 74fbaade9..6c748aed1 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -4,7 +4,7 @@ Create a full-text search index for offline search. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import html @@ -13,13 +13,12 @@ import re import warnings from importlib import import_module from os import path -from typing import Any, Dict, IO, Iterable, List, Tuple, Set +from typing import IO, Any, Dict, Iterable, List, Set, Tuple from docutils import nodes from docutils.nodes import Node -from sphinx import addnodes -from sphinx import package_dir +from sphinx import addnodes, package_dir from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.environment import BuildEnvironment from sphinx.search.jssplitter import splitter_code @@ -117,7 +116,7 @@ var Stemmer = function() { len(word) == 0 or not ( ((len(word) < 3) and (12353 < ord(word[0]) < 12436)) or (ord(word[0]) < 256 and ( - len(word) < 3 or word in self.stopwords or word.isdigit() + len(word) < 3 or word in self.stopwords )))) diff --git a/sphinx/search/da.py b/sphinx/search/da.py index b04679e10..e164e0271 100644 --- a/sphinx/search/da.py +++ b/sphinx/search/da.py @@ -4,7 +4,7 @@ Danish search language: includes the JS Danish stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - danish_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/danish/stop.txt og | and diff --git a/sphinx/search/de.py b/sphinx/search/de.py index ae1827bf9..174eb8d2f 100644 --- a/sphinx/search/de.py +++ b/sphinx/search/de.py @@ -4,7 +4,7 @@ German search language: includes the JS German stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - german_stopwords = parse_stop_word(''' |source: http://snowball.tartarus.org/algorithms/german/stop.txt aber | but diff --git a/sphinx/search/en.py b/sphinx/search/en.py index 23a6f9739..b33769cec 100644 --- a/sphinx/search/en.py +++ b/sphinx/search/en.py @@ -4,7 +4,7 @@ English search language: includes the JS porter stemmer. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/search/es.py b/sphinx/search/es.py index 1009961c8..e87584cfc 100644 --- a/sphinx/search/es.py +++ b/sphinx/search/es.py @@ -4,7 +4,7 @@ Spanish search language: includes the JS Spanish stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - spanish_stopwords = parse_stop_word(''' |source: http://snowball.tartarus.org/algorithms/spanish/stop.txt de | from, of diff --git a/sphinx/search/fi.py b/sphinx/search/fi.py index 67bee89fe..ceb38cb5a 100644 --- a/sphinx/search/fi.py +++ b/sphinx/search/fi.py @@ -4,7 +4,7 @@ Finnish search language: includes the JS Finnish stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - finnish_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/finnish/stop.txt | forms of BE diff --git a/sphinx/search/fr.py b/sphinx/search/fr.py index b15271888..46320a863 100644 --- a/sphinx/search/fr.py +++ b/sphinx/search/fr.py @@ -4,7 +4,7 @@ French search language: includes the JS French stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - french_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/french/stop.txt au | a + le diff --git a/sphinx/search/hu.py b/sphinx/search/hu.py index 085773383..628dde63e 100644 --- a/sphinx/search/hu.py +++ b/sphinx/search/hu.py @@ -4,7 +4,7 @@ Hungarian search language: includes the JS Hungarian stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - hungarian_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/hungarian/stop.txt | prepared by Anna Tordai diff --git a/sphinx/search/it.py b/sphinx/search/it.py index e76cd99dd..2ecf4c2c5 100644 --- a/sphinx/search/it.py +++ b/sphinx/search/it.py @@ -4,7 +4,7 @@ Italian search language: includes the JS Italian stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - italian_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/italian/stop.txt ad | a (to) before vowel diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py index d1f444be1..6f10a4239 100644 --- a/sphinx/search/ja.py +++ b/sphinx/search/ja.py @@ -4,7 +4,7 @@ Japanese search language: includes routine to split words. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -33,7 +33,7 @@ try: except ImportError: janome_module = False -from sphinx.errors import SphinxError, ExtensionError +from sphinx.errors import ExtensionError, SphinxError from sphinx.search import SearchLanguage from sphinx.util import import_object @@ -528,9 +528,9 @@ class SearchJapanese(SearchLanguage): dotted_path = options.get('type', 'sphinx.search.ja.DefaultSplitter') try: self.splitter = import_object(dotted_path)(options) - except ExtensionError: + except ExtensionError as exc: raise ExtensionError("Splitter module %r can't be imported" % - dotted_path) + dotted_path) from exc def split(self, input: str) -> List[str]: return self.splitter.split(input) diff --git a/sphinx/search/jssplitter.py b/sphinx/search/jssplitter.py index 945579560..9b879772a 100644 --- a/sphinx/search/jssplitter.py +++ b/sphinx/search/jssplitter.py @@ -6,7 +6,7 @@ DO NOT EDIT. This is generated by utils/jssplitter_generator.py - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/search/nl.py b/sphinx/search/nl.py index 0e2e2ef23..f98cdf8ad 100644 --- a/sphinx/search/nl.py +++ b/sphinx/search/nl.py @@ -4,7 +4,7 @@ Dutch search language: includes the JS porter stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - dutch_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/dutch/stop.txt de | the diff --git a/sphinx/search/no.py b/sphinx/search/no.py index 68c1ac207..c78bb6981 100644 --- a/sphinx/search/no.py +++ b/sphinx/search/no.py @@ -4,7 +4,7 @@ Norwegian search language: includes the JS Norwegian stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - norwegian_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/norwegian/stop.txt og | and diff --git a/sphinx/search/non-minified-js/danish-stemmer.js b/sphinx/search/non-minified-js/danish-stemmer.js index f6309327f..36943d22a 100644 --- a/sphinx/search/non-minified-js/danish-stemmer.js +++ b/sphinx/search/non-minified-js/danish-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/dutch-stemmer.js b/sphinx/search/non-minified-js/dutch-stemmer.js index 15c053a8d..997f1467b 100644 --- a/sphinx/search/non-minified-js/dutch-stemmer.js +++ b/sphinx/search/non-minified-js/dutch-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/finnish-stemmer.js b/sphinx/search/non-minified-js/finnish-stemmer.js index 210c3e13d..5b520c00f 100644 --- a/sphinx/search/non-minified-js/finnish-stemmer.js +++ b/sphinx/search/non-minified-js/finnish-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/french-stemmer.js b/sphinx/search/non-minified-js/french-stemmer.js index 3b3c0607f..75255a03d 100644 --- a/sphinx/search/non-minified-js/french-stemmer.js +++ b/sphinx/search/non-minified-js/french-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/german-stemmer.js b/sphinx/search/non-minified-js/german-stemmer.js index 4f1dc1cf3..a5beb8f3a 100644 --- a/sphinx/search/non-minified-js/german-stemmer.js +++ b/sphinx/search/non-minified-js/german-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/hungarian-stemmer.js b/sphinx/search/non-minified-js/hungarian-stemmer.js index c9a6347c6..67fd1cdf0 100644 --- a/sphinx/search/non-minified-js/hungarian-stemmer.js +++ b/sphinx/search/non-minified-js/hungarian-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/italian-stemmer.js b/sphinx/search/non-minified-js/italian-stemmer.js index ca16ff24c..52daef58f 100644 --- a/sphinx/search/non-minified-js/italian-stemmer.js +++ b/sphinx/search/non-minified-js/italian-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/norwegian-stemmer.js b/sphinx/search/non-minified-js/norwegian-stemmer.js index 38b64c5a8..5c6eba182 100644 --- a/sphinx/search/non-minified-js/norwegian-stemmer.js +++ b/sphinx/search/non-minified-js/norwegian-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/porter-stemmer.js b/sphinx/search/non-minified-js/porter-stemmer.js index 7a0f4558a..d07e7a426 100644 --- a/sphinx/search/non-minified-js/porter-stemmer.js +++ b/sphinx/search/non-minified-js/porter-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/portuguese-stemmer.js b/sphinx/search/non-minified-js/portuguese-stemmer.js index 35f21aa8f..4042c0aef 100644 --- a/sphinx/search/non-minified-js/portuguese-stemmer.js +++ b/sphinx/search/non-minified-js/portuguese-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/romanian-stemmer.js b/sphinx/search/non-minified-js/romanian-stemmer.js index f71f44a68..545d3ee2e 100644 --- a/sphinx/search/non-minified-js/romanian-stemmer.js +++ b/sphinx/search/non-minified-js/romanian-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/russian-stemmer.js b/sphinx/search/non-minified-js/russian-stemmer.js index 74d630968..87f4844e0 100644 --- a/sphinx/search/non-minified-js/russian-stemmer.js +++ b/sphinx/search/non-minified-js/russian-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/spanish-stemmer.js b/sphinx/search/non-minified-js/spanish-stemmer.js index 21b648fa8..6c5d2da91 100644 --- a/sphinx/search/non-minified-js/spanish-stemmer.js +++ b/sphinx/search/non-minified-js/spanish-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/swedish-stemmer.js b/sphinx/search/non-minified-js/swedish-stemmer.js index fd2a58f0a..1d8aba8f4 100644 --- a/sphinx/search/non-minified-js/swedish-stemmer.js +++ b/sphinx/search/non-minified-js/swedish-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/non-minified-js/turkish-stemmer.js b/sphinx/search/non-minified-js/turkish-stemmer.js index f8f088576..22bd7538d 100644 --- a/sphinx/search/non-minified-js/turkish-stemmer.js +++ b/sphinx/search/non-minified-js/turkish-stemmer.js @@ -143,7 +143,7 @@ JSX.resetProfileResults = function () { return $__jsx_profiler.resetResults(); }; JSX.DEBUG = false; -var GeneratorFunction$0 = +var GeneratorFunction$0 = (function () { try { return Function('import {GeneratorFunction} from "std:iteration"; return GeneratorFunction')(); @@ -151,7 +151,7 @@ var GeneratorFunction$0 = return function GeneratorFunction () {}; } })(); -var __jsx_generator_object$0 = +var __jsx_generator_object$0 = (function () { function __jsx_generator_object() { this.__next = 0; diff --git a/sphinx/search/pt.py b/sphinx/search/pt.py index 2538511f7..a7d99cde3 100644 --- a/sphinx/search/pt.py +++ b/sphinx/search/pt.py @@ -4,7 +4,7 @@ Portuguese search language: includes the JS Portuguese stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - portuguese_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/portuguese/stop.txt de | of, from diff --git a/sphinx/search/ro.py b/sphinx/search/ro.py index cfae772c9..6400967c6 100644 --- a/sphinx/search/ro.py +++ b/sphinx/search/ro.py @@ -4,7 +4,7 @@ Romanian search language: includes the JS Romanian stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage - js_stemmer = """ var JSX={};(function(j){function l(b,e){var a=function(){};a.prototype=e.prototype;var c=new a;for(var d in b){b[d].prototype=c}}function L(c,b){for(var a in b.prototype)if(b.prototype.hasOwnProperty(a))c.prototype[a]=b.prototype[a]}function h(a,b,d){function c(a,b,c){delete a[b];a[b]=c;return c}Object.defineProperty(a,b,{get:function(){return c(a,b,d())},set:function(d){c(a,b,d)},enumerable:true,configurable:true})}function M(a,b,c){return a[b]=a[b]/c|0}var E=parseInt;var C=parseFloat;function N(a){return a!==a}var A=isFinite;var z=encodeURIComponent;var y=decodeURIComponent;var x=encodeURI;var w=decodeURI;var u=Object.prototype.toString;var D=Object.prototype.hasOwnProperty;function k(){}j.require=function(b){var a=r[b];return a!==undefined?a:null};j.profilerIsRunning=function(){return k.getResults!=null};j.getProfileResults=function(){return(k.getResults||function(){return{}})()};j.postProfileResults=function(a,b){if(k.postResults==null)throw new Error('profiler has not been turned on');return k.postResults(a,b)};j.resetProfileResults=function(){if(k.resetResults==null)throw new Error('profiler has not been turned on');return k.resetResults()};j.DEBUG=false;function t(){};l([t],Error);function a(a,b,c){this.F=a.length;this.K=a;this.L=b;this.I=c;this.H=null;this.P=null};l([a],Object);function n(){};l([n],Object);function g(){var a;var b;var c;this.G={};a=this.E='';b=this._=0;c=this.A=a.length;this.D=0;this.B=b;this.C=c};l([g],n);function v(a,b){a.E=b.E;a._=b._;a.A=b.A;a.D=b.D;a.B=b.B;a.C=b.C};function d(b,d,c,e){var a;if(b._>=b.A){return false}a=b.E.charCodeAt(b._);if(a>e||a<c){return false}a-=c;if((d[a>>>3]&1<<(a&7))===0){return false}b._++;return true};function e(a,d,c,e){var b;if(a._>=a.A){return false}b=a.E.charCodeAt(a._);if(b>e||b<c){a._++;return true}b-=c;if((d[b>>>3]&1<<(b&7))===0){a._++;return true}return false};function p(a,d,c,e){var b;if(a._<=a.D){return false}b=a.E.charCodeAt(a._-1);if(b>e||b<c){a._--;return true}b-=c;if((d[b>>>3]&1<<(b&7))===0){a._--;return true}return false};function m(a,b,d){var c;if(a.A-a._<b){return false}if(a.E.slice(c=a._,c+b)!==d){return false}a._+=b;return true};function i(a,b,d){var c;if(a._-a.D<b){return false}if(a.E.slice((c=a._)-b,c)!==d){return false}a._-=b;return true};function q(f,m,p){var b;var d;var e;var n;var g;var k;var l;var i;var h;var c;var a;var j;var o;b=0;d=p;e=f._;n=f.A;g=0;k=0;l=false;while(true){i=b+(d-b>>>1);h=0;c=g<k?g:k;a=m[i];for(j=c;j<a.F;j++){if(e+c===n){h=-1;break}h=f.E.charCodeAt(e+c)-a.K.charCodeAt(j);if(h!==0){break}c++}if(h<0){d=i;k=c}else{b=i;g=c}if(d-b<=1){if(b>0){break}if(d===b){break}if(l){break}l=true}}while(true){a=m[b];if(g>=a.F){f._=e+a.F|0;if(a.H==null){return a.I}o=a.H(a.P);f._=e+a.F|0;if(o){return a.I}}b=a.L;if(b<0){return 0}}return-1};function f(d,m,p){var b;var g;var e;var n;var f;var k;var l;var i;var h;var c;var a;var j;var o;b=0;g=p;e=d._;n=d.D;f=0;k=0;l=false;while(true){i=b+(g-b>>1);h=0;c=f<k?f:k;a=m[i];for(j=a.F-1-c;j>=0;j--){if(e-c===n){h=-1;break}h=d.E.charCodeAt(e-1-c)-a.K.charCodeAt(j);if(h!==0){break}c++}if(h<0){g=i;k=c}else{b=i;f=c}if(g-b<=1){if(b>0){break}if(g===b){break}if(l){break}l=true}}while(true){a=m[b];if(f>=a.F){d._=e-a.F|0;if(a.H==null){return a.I}o=a.H(d);d._=e-a.F|0;if(o){return a.I}}b=a.L;if(b<0){return 0}}return-1};function s(a,b,d,e){var c;c=e.length-(d-b);a.E=a.E.slice(0,b)+e+a.E.slice(d);a.A+=c|0;if(a._>=d){a._+=c|0}else if(a._>b){a._=b}return c|0};function c(a,f){var b;var c;var d;var e;b=false;if((c=a.B)<0||c>(d=a.C)||d>(e=a.A)||e>a.E.length?false:true){s(a,a.B,a.C,f);b=true}return b};g.prototype.J=function(){return false};g.prototype.b=function(b){var a;var c;var d;var e;a=this.G['.'+b];if(a==null){c=this.E=b;d=this._=0;e=this.A=c.length;this.D=0;this.B=d;this.C=e;this.J();a=this.E;this.G['.'+b]=a}return a};g.prototype.stemWord=g.prototype.b;g.prototype.c=function(e){var d;var b;var c;var a;var f;var g;var h;d=[];for(b=0;b<e.length;b++){c=e[b];a=this.G['.'+c];if(a==null){f=this.E=c;g=this._=0;h=this.A=f.length;this.D=0;this.B=g;this.C=h;this.J();a=this.E;this.G['.'+c]=a}d.push(a)}return d};g.prototype.stemWords=g.prototype.c;function b(){g.call(this);this.B_standard_suffix_removed=false;this.I_p2=0;this.I_p1=0;this.I_pV=0};l([b],g);b.prototype.M=function(a){this.B_standard_suffix_removed=a.B_standard_suffix_removed;this.I_p2=a.I_p2;this.I_p1=a.I_p1;this.I_pV=a.I_pV;v(this,a)};b.prototype.copy_from=b.prototype.M;b.prototype.W=function(){var i;var a;var j;var e;var f;var g;var h;var k;b:while(true){i=this._;e=true;d:while(e===true){e=false;e:while(true){a=this._;f=true;a:while(f===true){f=false;if(!d(this,b.g_v,97,259)){break a}this.B=this._;g=true;f:while(g===true){g=false;j=this._;h=true;c:while(h===true){h=false;if(!m(this,1,'u')){break c}this.C=this._;if(!d(this,b.g_v,97,259)){break c}if(!c(this,'U')){return false}break f}this._=j;if(!m(this,1,'i')){break a}this.C=this._;if(!d(this,b.g_v,97,259)){break a}if(!c(this,'I')){return false}}this._=a;break e}k=this._=a;if(k>=this.A){break d}this._++}continue b}this._=i;break b}return true};b.prototype.r_prelude=b.prototype.W;function G(a){var j;var e;var k;var f;var g;var h;var i;var l;b:while(true){j=a._;f=true;d:while(f===true){f=false;e:while(true){e=a._;g=true;a:while(g===true){g=false;if(!d(a,b.g_v,97,259)){break a}a.B=a._;h=true;f:while(h===true){h=false;k=a._;i=true;c:while(i===true){i=false;if(!m(a,1,'u')){break c}a.C=a._;if(!d(a,b.g_v,97,259)){break c}if(!c(a,'U')){return false}break f}a._=k;if(!m(a,1,'i')){break a}a.C=a._;if(!d(a,b.g_v,97,259)){break a}if(!c(a,'I')){return false}}a._=e;break e}l=a._=e;if(l>=a.A){break d}a._++}continue b}a._=j;break b}return true};b.prototype.U=function(){var u;var w;var x;var y;var t;var l;var f;var g;var h;var i;var c;var j;var k;var a;var m;var n;var o;var p;var q;var r;var s;var v;this.I_pV=s=this.A;this.I_p1=s;this.I_p2=s;u=this._;l=true;a:while(l===true){l=false;f=true;g:while(f===true){f=false;w=this._;g=true;b:while(g===true){g=false;if(!d(this,b.g_v,97,259)){break b}h=true;f:while(h===true){h=false;x=this._;i=true;c:while(i===true){i=false;if(!e(this,b.g_v,97,259)){break c}d:while(true){c=true;e:while(c===true){c=false;if(!d(this,b.g_v,97,259)){break e}break d}if(this._>=this.A){break c}this._++}break f}this._=x;if(!d(this,b.g_v,97,259)){break b}c:while(true){j=true;d:while(j===true){j=false;if(!e(this,b.g_v,97,259)){break d}break c}if(this._>=this.A){break b}this._++}}break g}this._=w;if(!e(this,b.g_v,97,259)){break a}k=true;c:while(k===true){k=false;y=this._;a=true;b:while(a===true){a=false;if(!e(this,b.g_v,97,259)){break b}e:while(true){m=true;d:while(m===true){m=false;if(!d(this,b.g_v,97,259)){break d}break e}if(this._>=this.A){break b}this._++}break c}this._=y;if(!d(this,b.g_v,97,259)){break a}if(this._>=this.A){break a}this._++}}this.I_pV=this._}v=this._=u;t=v;n=true;a:while(n===true){n=false;b:while(true){o=true;c:while(o===true){o=false;if(!d(this,b.g_v,97,259)){break c}break b}if(this._>=this.A){break a}this._++}b:while(true){p=true;c:while(p===true){p=false;if(!e(this,b.g_v,97,259)){break c}break b}if(this._>=this.A){break a}this._++}this.I_p1=this._;b:while(true){q=true;c:while(q===true){q=false;if(!d(this,b.g_v,97,259)){break c}break b}if(this._>=this.A){break a}this._++}c:while(true){r=true;b:while(r===true){r=false;if(!e(this,b.g_v,97,259)){break b}break c}if(this._>=this.A){break a}this._++}this.I_p2=this._}this._=t;return true};b.prototype.r_mark_regions=b.prototype.U;function H(a){var x;var y;var z;var u;var v;var l;var f;var g;var h;var i;var j;var k;var c;var m;var n;var o;var p;var q;var r;var s;var t;var w;a.I_pV=t=a.A;a.I_p1=t;a.I_p2=t;x=a._;l=true;a:while(l===true){l=false;f=true;g:while(f===true){f=false;y=a._;g=true;b:while(g===true){g=false;if(!d(a,b.g_v,97,259)){break b}h=true;f:while(h===true){h=false;z=a._;i=true;c:while(i===true){i=false;if(!e(a,b.g_v,97,259)){break c}d:while(true){j=true;e:while(j===true){j=false;if(!d(a,b.g_v,97,259)){break e}break d}if(a._>=a.A){break c}a._++}break f}a._=z;if(!d(a,b.g_v,97,259)){break b}c:while(true){k=true;d:while(k===true){k=false;if(!e(a,b.g_v,97,259)){break d}break c}if(a._>=a.A){break b}a._++}}break g}a._=y;if(!e(a,b.g_v,97,259)){break a}c=true;c:while(c===true){c=false;u=a._;m=true;b:while(m===true){m=false;if(!e(a,b.g_v,97,259)){break b}e:while(true){n=true;d:while(n===true){n=false;if(!d(a,b.g_v,97,259)){break d}break e}if(a._>=a.A){break b}a._++}break c}a._=u;if(!d(a,b.g_v,97,259)){break a}if(a._>=a.A){break a}a._++}}a.I_pV=a._}w=a._=x;v=w;o=true;a:while(o===true){o=false;b:while(true){p=true;c:while(p===true){p=false;if(!d(a,b.g_v,97,259)){break c}break b}if(a._>=a.A){break a}a._++}b:while(true){q=true;c:while(q===true){q=false;if(!e(a,b.g_v,97,259)){break c}break b}if(a._>=a.A){break a}a._++}a.I_p1=a._;b:while(true){r=true;c:while(r===true){r=false;if(!d(a,b.g_v,97,259)){break c}break b}if(a._>=a.A){break a}a._++}c:while(true){s=true;b:while(s===true){s=false;if(!e(a,b.g_v,97,259)){break b}break c}if(a._>=a.A){break a}a._++}a.I_p2=a._}a._=v;return true};b.prototype.V=function(){var a;var e;var d;b:while(true){e=this._;d=true;a:while(d===true){d=false;this.B=this._;a=q(this,b.a_0,3);if(a===0){break a}this.C=this._;switch(a){case 0:break a;case 1:if(!c(this,'i')){return false}break;case 2:if(!c(this,'u')){return false}break;case 3:if(this._>=this.A){break a}this._++;break}continue b}this._=e;break b}return true};b.prototype.r_postlude=b.prototype.V;function I(a){var d;var f;var e;b:while(true){f=a._;e=true;a:while(e===true){e=false;a.B=a._;d=q(a,b.a_0,3);if(d===0){break a}a.C=a._;switch(d){case 0:break a;case 1:if(!c(a,'i')){return false}break;case 2:if(!c(a,'u')){return false}break;case 3:if(a._>=a.A){break a}a._++;break}continue b}a._=f;break b}return true};b.prototype.S=function(){return!(this.I_pV<=this._)?false:true};b.prototype.r_RV=b.prototype.S;b.prototype.Q=function(){return!(this.I_p1<=this._)?false:true};b.prototype.r_R1=b.prototype.Q;b.prototype.R=function(){return!(this.I_p2<=this._)?false:true};b.prototype.r_R2=b.prototype.R;b.prototype.Y=function(){var a;var e;var d;var g;this.C=this._;a=f(this,b.a_1,16);if(a===0){return false}this.B=g=this._;if(!(!(this.I_p1<=g)?false:true)){return false}switch(a){case 0:return false;case 1:if(!c(this,'')){return false}break;case 2:if(!c(this,'a')){return false}break;case 3:if(!c(this,'e')){return false}break;case 4:if(!c(this,'i')){return false}break;case 5:e=this.A-this._;d=true;a:while(d===true){d=false;if(!i(this,2,'ab')){break a}return false}this._=this.A-e;if(!c(this,'i')){return false}break;case 6:if(!c(this,'at')){return false}break;case 7:if(!c(this,'aţi')){return false}break}return true};b.prototype.r_step_0=b.prototype.Y;function J(a){var d;var g;var e;var h;a.C=a._;d=f(a,b.a_1,16);if(d===0){return false}a.B=h=a._;if(!(!(a.I_p1<=h)?false:true)){return false}switch(d){case 0:return false;case 1:if(!c(a,'')){return false}break;case 2:if(!c(a,'a')){return false}break;case 3:if(!c(a,'e')){return false}break;case 4:if(!c(a,'i')){return false}break;case 5:g=a.A-a._;e=true;a:while(e===true){e=false;if(!i(a,2,'ab')){break a}return false}a._=a.A-g;if(!c(a,'i')){return false}break;case 6:if(!c(a,'at')){return false}break;case 7:if(!c(a,'aţi')){return false}break}return true};b.prototype.T=function(){var a;var d;var e;var g;d=this.A-(e=this._);this.C=e;a=f(this,b.a_2,46);if(a===0){return false}this.B=g=this._;if(!(!(this.I_p1<=g)?false:true)){return false}switch(a){case 0:return false;case 1:if(!c(this,'abil')){return false}break;case 2:if(!c(this,'ibil')){return false}break;case 3:if(!c(this,'iv')){return false}break;case 4:if(!c(this,'ic')){return false}break;case 5:if(!c(this,'at')){return false}break;case 6:if(!c(this,'it')){return false}break}this.B_standard_suffix_removed=true;this._=this.A-d;return true};b.prototype.r_combo_suffix=b.prototype.T;function o(a){var d;var e;var g;var h;e=a.A-(g=a._);a.C=g;d=f(a,b.a_2,46);if(d===0){return false}a.B=h=a._;if(!(!(a.I_p1<=h)?false:true)){return false}switch(d){case 0:return false;case 1:if(!c(a,'abil')){return false}break;case 2:if(!c(a,'ibil')){return false}break;case 3:if(!c(a,'iv')){return false}break;case 4:if(!c(a,'ic')){return false}break;case 5:if(!c(a,'at')){return false}break;case 6:if(!c(a,'it')){return false}break}a.B_standard_suffix_removed=true;a._=a.A-e;return true};b.prototype.X=function(){var a;var e;var d;var g;this.B_standard_suffix_removed=false;a:while(true){e=this.A-this._;d=true;b:while(d===true){d=false;if(!o(this)){break b}continue a}this._=this.A-e;break a}this.C=this._;a=f(this,b.a_3,62);if(a===0){return false}this.B=g=this._;if(!(!(this.I_p2<=g)?false:true)){return false}switch(a){case 0:return false;case 1:if(!c(this,'')){return false}break;case 2:if(!i(this,1,'ţ')){return false}this.B=this._;if(!c(this,'t')){return false}break;case 3:if(!c(this,'ist')){return false}break}this.B_standard_suffix_removed=true;return true};b.prototype.r_standard_suffix=b.prototype.X;function K(a){var d;var g;var e;var h;a.B_standard_suffix_removed=false;a:while(true){g=a.A-a._;e=true;b:while(e===true){e=false;if(!o(a)){break b}continue a}a._=a.A-g;break a}a.C=a._;d=f(a,b.a_3,62);if(d===0){return false}a.B=h=a._;if(!(!(a.I_p2<=h)?false:true)){return false}switch(d){case 0:return false;case 1:if(!c(a,'')){return false}break;case 2:if(!i(a,1,'ţ')){return false}a.B=a._;if(!c(a,'t')){return false}break;case 3:if(!c(a,'ist')){return false}break}a.B_standard_suffix_removed=true;return true};b.prototype.Z=function(){var d;var h;var a;var j;var e;var g;var k;var l;var m;h=this.A-(k=this._);if(k<this.I_pV){return false}l=this._=this.I_pV;a=this.D;this.D=l;m=this._=this.A-h;this.C=m;d=f(this,b.a_4,94);if(d===0){this.D=a;return false}this.B=this._;switch(d){case 0:this.D=a;return false;case 1:e=true;a:while(e===true){e=false;j=this.A-this._;g=true;b:while(g===true){g=false;if(!p(this,b.g_v,97,259)){break b}break a}this._=this.A-j;if(!i(this,1,'u')){this.D=a;return false}}if(!c(this,'')){return false}break;case 2:if(!c(this,'')){return false}break}this.D=a;return true};b.prototype.r_verb_suffix=b.prototype.Z;function F(a){var e;var l;var d;var j;var g;var h;var m;var n;var k;l=a.A-(m=a._);if(m<a.I_pV){return false}n=a._=a.I_pV;d=a.D;a.D=n;k=a._=a.A-l;a.C=k;e=f(a,b.a_4,94);if(e===0){a.D=d;return false}a.B=a._;switch(e){case 0:a.D=d;return false;case 1:g=true;a:while(g===true){g=false;j=a.A-a._;h=true;b:while(h===true){h=false;if(!p(a,b.g_v,97,259)){break b}break a}a._=a.A-j;if(!i(a,1,'u')){a.D=d;return false}}if(!c(a,'')){return false}break;case 2:if(!c(a,'')){return false}break}a.D=d;return true};b.prototype.a=function(){var a;var d;this.C=this._;a=f(this,b.a_5,5);if(a===0){return false}this.B=d=this._;if(!(!(this.I_pV<=d)?false:true)){return false}switch(a){case 0:return false;case 1:if(!c(this,'')){return false}break}return true};b.prototype.r_vowel_suffix=b.prototype.a;function B(a){var d;var e;a.C=a._;d=f(a,b.a_5,5);if(d===0){return false}a.B=e=a._;if(!(!(a.I_pV<=e)?false:true)){return false}switch(d){case 0:return false;case 1:if(!c(a,'')){return false}break}return true};b.prototype.J=function(){var n;var j;var k;var l;var m;var o;var p;var b;var c;var d;var e;var f;var a;var g;var h;var i;var r;var s;var t;var u;var v;var w;var x;var y;var q;n=this._;b=true;a:while(b===true){b=false;if(!G(this)){break a}}r=this._=n;j=r;c=true;a:while(c===true){c=false;if(!H(this)){break a}}s=this._=j;this.D=s;u=this._=t=this.A;k=t-u;d=true;a:while(d===true){d=false;if(!J(this)){break a}}w=this._=(v=this.A)-k;l=v-w;e=true;a:while(e===true){e=false;if(!K(this)){break a}}y=this._=(x=this.A)-l;m=x-y;f=true;a:while(f===true){f=false;a=true;b:while(a===true){a=false;o=this.A-this._;g=true;c:while(g===true){g=false;if(!this.B_standard_suffix_removed){break c}break b}this._=this.A-o;if(!F(this)){break a}}}this._=this.A-m;h=true;a:while(h===true){h=false;if(!B(this)){break a}}q=this._=this.D;p=q;i=true;a:while(i===true){i=false;if(!I(this)){break a}}this._=p;return true};b.prototype.stem=b.prototype.J;b.prototype.N=function(a){return a instanceof b};b.prototype.equals=b.prototype.N;b.prototype.O=function(){var c;var a;var b;var d;c='RomanianStemmer';a=0;for(b=0;b<c.length;b++){d=c.charCodeAt(b);a=(a<<5)-a+d;a=a&a}return a|0};b.prototype.hashCode=b.prototype.O;b.serialVersionUID=1;h(b,'methodObject',function(){return new b});h(b,'a_0',function(){return[new a('',-1,3),new a('I',0,1),new a('U',0,2)]});h(b,'a_1',function(){return[new a('ea',-1,3),new a('aţia',-1,7),new a('aua',-1,2),new a('iua',-1,4),new a('aţie',-1,7),new a('ele',-1,3),new a('ile',-1,5),new a('iile',6,4),new a('iei',-1,4),new a('atei',-1,6),new a('ii',-1,4),new a('ului',-1,1),new a('ul',-1,1),new a('elor',-1,3),new a('ilor',-1,4),new a('iilor',14,4)]});h(b,'a_2',function(){return[new a('icala',-1,4),new a('iciva',-1,4),new a('ativa',-1,5),new a('itiva',-1,6),new a('icale',-1,4),new a('aţiune',-1,5),new a('iţiune',-1,6),new a('atoare',-1,5),new a('itoare',-1,6),new a('ătoare',-1,5),new a('icitate',-1,4),new a('abilitate',-1,1),new a('ibilitate',-1,2),new a('ivitate',-1,3),new a('icive',-1,4),new a('ative',-1,5),new a('itive',-1,6),new a('icali',-1,4),new a('atori',-1,5),new a('icatori',18,4),new a('itori',-1,6),new a('ători',-1,5),new a('icitati',-1,4),new a('abilitati',-1,1),new a('ivitati',-1,3),new a('icivi',-1,4),new a('ativi',-1,5),new a('itivi',-1,6),new a('icităi',-1,4),new a('abilităi',-1,1),new a('ivităi',-1,3),new a('icităţi',-1,4),new a('abilităţi',-1,1),new a('ivităţi',-1,3),new a('ical',-1,4),new a('ator',-1,5),new a('icator',35,4),new a('itor',-1,6),new a('ător',-1,5),new a('iciv',-1,4),new a('ativ',-1,5),new a('itiv',-1,6),new a('icală',-1,4),new a('icivă',-1,4),new a('ativă',-1,5),new a('itivă',-1,6)]});h(b,'a_3',function(){return[new a('ica',-1,1),new a('abila',-1,1),new a('ibila',-1,1),new a('oasa',-1,1),new a('ata',-1,1),new a('ita',-1,1),new a('anta',-1,1),new a('ista',-1,3),new a('uta',-1,1),new a('iva',-1,1),new a('ic',-1,1),new a('ice',-1,1),new a('abile',-1,1),new a('ibile',-1,1),new a('isme',-1,3),new a('iune',-1,2),new a('oase',-1,1),new a('ate',-1,1),new a('itate',17,1),new a('ite',-1,1),new a('ante',-1,1),new a('iste',-1,3),new a('ute',-1,1),new a('ive',-1,1),new a('ici',-1,1),new a('abili',-1,1),new a('ibili',-1,1),new a('iuni',-1,2),new a('atori',-1,1),new a('osi',-1,1),new a('ati',-1,1),new a('itati',30,1),new a('iti',-1,1),new a('anti',-1,1),new a('isti',-1,3),new a('uti',-1,1),new a('işti',-1,3),new a('ivi',-1,1),new a('ităi',-1,1),new a('oşi',-1,1),new a('ităţi',-1,1),new a('abil',-1,1),new a('ibil',-1,1),new a('ism',-1,3),new a('ator',-1,1),new a('os',-1,1),new a('at',-1,1),new a('it',-1,1),new a('ant',-1,1),new a('ist',-1,3),new a('ut',-1,1),new a('iv',-1,1),new a('ică',-1,1),new a('abilă',-1,1),new a('ibilă',-1,1),new a('oasă',-1,1),new a('ată',-1,1),new a('ită',-1,1),new a('antă',-1,1),new a('istă',-1,3),new a('ută',-1,1),new a('ivă',-1,1)]});h(b,'a_4',function(){return[new a('ea',-1,1),new a('ia',-1,1),new a('esc',-1,1),new a('ăsc',-1,1),new a('ind',-1,1),new a('ând',-1,1),new a('are',-1,1),new a('ere',-1,1),new a('ire',-1,1),new a('âre',-1,1),new a('se',-1,2),new a('ase',10,1),new a('sese',10,2),new a('ise',10,1),new a('use',10,1),new a('âse',10,1),new a('eşte',-1,1),new a('ăşte',-1,1),new a('eze',-1,1),new a('ai',-1,1),new a('eai',19,1),new a('iai',19,1),new a('sei',-1,2),new a('eşti',-1,1),new a('ăşti',-1,1),new a('ui',-1,1),new a('ezi',-1,1),new a('âi',-1,1),new a('aşi',-1,1),new a('seşi',-1,2),new a('aseşi',29,1),new a('seseşi',29,2),new a('iseşi',29,1),new a('useşi',29,1),new a('âseşi',29,1),new a('işi',-1,1),new a('uşi',-1,1),new a('âşi',-1,1),new a('aţi',-1,2),new a('eaţi',38,1),new a('iaţi',38,1),new a('eţi',-1,2),new a('iţi',-1,2),new a('âţi',-1,2),new a('arăţi',-1,1),new a('serăţi',-1,2),new a('aserăţi',45,1),new a('seserăţi',45,2),new a('iserăţi',45,1),new a('userăţi',45,1),new a('âserăţi',45,1),new a('irăţi',-1,1),new a('urăţi',-1,1),new a('ârăţi',-1,1),new a('am',-1,1),new a('eam',54,1),new a('iam',54,1),new a('em',-1,2),new a('asem',57,1),new a('sesem',57,2),new a('isem',57,1),new a('usem',57,1),new a('âsem',57,1),new a('im',-1,2),new a('âm',-1,2),new a('ăm',-1,2),new a('arăm',65,1),new a('serăm',65,2),new a('aserăm',67,1),new a('seserăm',67,2),new a('iserăm',67,1),new a('userăm',67,1),new a('âserăm',67,1),new a('irăm',65,1),new a('urăm',65,1),new a('ârăm',65,1),new a('au',-1,1),new a('eau',76,1),new a('iau',76,1),new a('indu',-1,1),new a('ându',-1,1),new a('ez',-1,1),new a('ească',-1,1),new a('ară',-1,1),new a('seră',-1,2),new a('aseră',84,1),new a('seseră',84,2),new a('iseră',84,1),new a('useră',84,1),new a('âseră',84,1),new a('iră',-1,1),new a('ură',-1,1),new a('âră',-1,1),new a('ează',-1,1)]});h(b,'a_5',function(){return[new a('a',-1,1),new a('e',-1,1),new a('ie',1,1),new a('i',-1,1),new a('ă',-1,1)]});h(b,'g_v',function(){return[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,32,0,0,4]});var r={'src/stemmer.jsx':{Stemmer:n},'src/romanian-stemmer.jsx':{RomanianStemmer:b}}}(JSX)) var Stemmer = JSX.require("src/romanian-stemmer.jsx").RomanianStemmer; diff --git a/sphinx/search/ru.py b/sphinx/search/ru.py index 9c0e30394..20ce14869 100644 --- a/sphinx/search/ru.py +++ b/sphinx/search/ru.py @@ -4,7 +4,7 @@ Russian search language: includes the JS Russian stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - russian_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/russian/stop.txt и | and diff --git a/sphinx/search/sv.py b/sphinx/search/sv.py index 4af7f7835..2ce4027ca 100644 --- a/sphinx/search/sv.py +++ b/sphinx/search/sv.py @@ -4,7 +4,7 @@ Swedish search language: includes the JS Swedish stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage, parse_stop_word - swedish_stopwords = parse_stop_word(''' | source: http://snowball.tartarus.org/algorithms/swedish/stop.txt och | and diff --git a/sphinx/search/tr.py b/sphinx/search/tr.py index 8db42f676..565e341fd 100644 --- a/sphinx/search/tr.py +++ b/sphinx/search/tr.py @@ -4,7 +4,7 @@ Turkish search language: includes the JS Turkish stemmer. - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,7 +14,6 @@ import snowballstemmer from sphinx.search import SearchLanguage - js_stemmer = """ var JSX={};(function(q){function r(b,e){var a=function(){};a.prototype=e.prototype;var c=new a;for(var d in b){b[d].prototype=c}}function Q(c,b){for(var a in b.prototype)if(b.prototype.hasOwnProperty(a))c.prototype[a]=b.prototype[a]}function j(a,b,d){function c(a,b,c){delete a[b];a[b]=c;return c}Object.defineProperty(a,b,{get:function(){return c(a,b,d())},set:function(d){c(a,b,d)},enumerable:true,configurable:true})}function R(a,b,c){return a[b]=a[b]/c|0}var M=parseInt;var K=parseFloat;function P(a){return a!==a}var A=isFinite;var G=encodeURIComponent;var F=decodeURIComponent;var E=encodeURI;var D=decodeURI;var C=Object.prototype.toString;var H=Object.prototype.hasOwnProperty;function p(){}q.require=function(b){var a=y[b];return a!==undefined?a:null};q.profilerIsRunning=function(){return p.getResults!=null};q.getProfileResults=function(){return(p.getResults||function(){return{}})()};q.postProfileResults=function(a,b){if(p.postResults==null)throw new Error('profiler has not been turned on');return p.postResults(a,b)};q.resetProfileResults=function(){if(p.resetResults==null)throw new Error('profiler has not been turned on');return p.resetResults()};q.DEBUG=false;function I(){};r([I],Error);function d(a,b,c){this.G=a.length;this.A_=a;this.D_=b;this.J=c;this.I=null;this.E_=null};r([d],Object);function u(){};r([u],Object);function m(){var a;var b;var c;this.F={};a=this.E='';b=this._=0;c=this.A=a.length;this.D=0;this.B=b;this.C=c};r([m],u);function B(a,b){a.E=b.E;a._=b._;a.A=b.A;a.D=b.D;a.B=b.B;a.C=b.C};function v(b,d,c,e){var a;if(b._>=b.A){return false}a=b.E.charCodeAt(b._);if(a>e||a<c){return false}a-=c;if((d[a>>>3]&1<<(a&7))===0){return false}b._++;return true};function f(b,d,c,e){var a;if(b._<=b.D){return false}a=b.E.charCodeAt(b._-1);if(a>e||a<c){return false}a-=c;if((d[a>>>3]&1<<(a&7))===0){return false}b._--;return true};function t(a,d,c,e){var b;if(a._<=a.D){return false}b=a.E.charCodeAt(a._-1);if(b>e||b<c){a._--;return true}b-=c;if((d[b>>>3]&1<<(b&7))===0){a._--;return true}return false};function s(a,b,d){var c;if(a.A-a._<b){return false}if(a.E.slice(c=a._,c+b)!==d){return false}a._+=b;return true};function g(a,b,d){var c;if(a._-a.D<b){return false}if(a.E.slice((c=a._)-b,c)!==d){return false}a._-=b;return true};function b(d,m,p){var b;var g;var e;var n;var f;var k;var l;var i;var h;var c;var a;var j;var o;b=0;g=p;e=d._;n=d.D;f=0;k=0;l=false;while(true){i=b+(g-b>>1);h=0;c=f<k?f:k;a=m[i];for(j=a.G-1-c;j>=0;j--){if(e-c===n){h=-1;break}h=d.E.charCodeAt(e-1-c)-a.A_.charCodeAt(j);if(h!==0){break}c++}if(h<0){g=i;k=c}else{b=i;f=c}if(g-b<=1){if(b>0){break}if(g===b){break}if(l){break}l=true}}while(true){a=m[b];if(f>=a.G){d._=e-a.G|0;if(a.I==null){return a.J}o=a.I(d);d._=e-a.G|0;if(o){return a.J}}b=a.D_;if(b<0){return 0}}return-1};function n(a,b,d,e){var c;c=e.length-(d-b);a.E=a.E.slice(0,b)+e+a.E.slice(d);a.A+=c|0;if(a._>=d){a._+=c|0}else if(a._>b){a._=b}return c|0};function e(a,f){var b;var c;var d;var e;b=false;if((c=a.B)<0||c>(d=a.C)||d>(e=a.A)||e>a.E.length?false:true){n(a,a.B,a.C,f);b=true}return b};m.prototype.H=function(){return false};m.prototype.B_=function(b){var a;var c;var d;var e;a=this.F['.'+b];if(a==null){c=this.E=b;d=this._=0;e=this.A=c.length;this.D=0;this.B=d;this.C=e;this.H();a=this.E;this.F['.'+b]=a}return a};m.prototype.stemWord=m.prototype.B_;m.prototype.C_=function(e){var d;var b;var c;var a;var f;var g;var h;d=[];for(b=0;b<e.length;b++){c=e[b];a=this.F['.'+c];if(a==null){f=this.E=c;g=this._=0;h=this.A=f.length;this.D=0;this.B=g;this.C=h;this.H();a=this.E;this.F['.'+c]=a}d.push(a)}return d};m.prototype.stemWords=m.prototype.C_;function a(){m.call(this);this.B_continue_stemming_noun_suffixes=false;this.I_strlen=0};r([a],m);a.prototype.K=function(a){this.B_continue_stemming_noun_suffixes=a.B_continue_stemming_noun_suffixes;this.I_strlen=a.I_strlen;B(this,a)};a.prototype.copy_from=a.prototype.K;a.prototype.O=function(){var E;var q;var b;var e;var h;var i;var j;var k;var l;var m;var n;var o;var p;var c;var r;var s;var t;var u;var d;var v;var w;var x;var y;var z;var A;var B;var C;var D;var G;var H;var I;var J;var K;var L;var M;var N;var F;E=this.A-this._;b:while(true){q=this.A-this._;o=true;a:while(o===true){o=false;if(!f(this,a.g_vowel,97,305)){break a}this._=this.A-q;break b}G=this._=this.A-q;if(G<=this.D){return false}this._--}p=true;a:while(p===true){p=false;b=this.A-this._;c=true;b:while(c===true){c=false;if(!g(this,1,'a')){break b}c:while(true){e=this.A-this._;r=true;d:while(r===true){r=false;if(!f(this,a.g_vowel1,97,305)){break d}this._=this.A-e;break c}H=this._=this.A-e;if(H<=this.D){break b}this._--}break a}this._=this.A-b;s=true;b:while(s===true){s=false;if(!g(this,1,'e')){break b}c:while(true){h=this.A-this._;t=true;d:while(t===true){t=false;if(!f(this,a.g_vowel2,101,252)){break d}this._=this.A-h;break c}I=this._=this.A-h;if(I<=this.D){break b}this._--}break a}this._=this.A-b;u=true;b:while(u===true){u=false;if(!g(this,1,'ı')){break b}c:while(true){i=this.A-this._;d=true;d:while(d===true){d=false;if(!f(this,a.g_vowel3,97,305)){break d}this._=this.A-i;break c}J=this._=this.A-i;if(J<=this.D){break b}this._--}break a}this._=this.A-b;v=true;b:while(v===true){v=false;if(!g(this,1,'i')){break b}c:while(true){j=this.A-this._;w=true;d:while(w===true){w=false;if(!f(this,a.g_vowel4,101,105)){break d}this._=this.A-j;break c}K=this._=this.A-j;if(K<=this.D){break b}this._--}break a}this._=this.A-b;x=true;b:while(x===true){x=false;if(!g(this,1,'o')){break b}c:while(true){k=this.A-this._;y=true;d:while(y===true){y=false;if(!f(this,a.g_vowel5,111,117)){break d}this._=this.A-k;break c}L=this._=this.A-k;if(L<=this.D){break b}this._--}break a}this._=this.A-b;z=true;b:while(z===true){z=false;if(!g(this,1,'ö')){break b}c:while(true){l=this.A-this._;A=true;d:while(A===true){A=false;if(!f(this,a.g_vowel6,246,252)){break d}this._=this.A-l;break c}M=this._=this.A-l;if(M<=this.D){break b}this._--}break a}this._=this.A-b;B=true;b:while(B===true){B=false;if(!g(this,1,'u')){break b}c:while(true){m=this.A-this._;C=true;d:while(C===true){C=false;if(!f(this,a.g_vowel5,111,117)){break d}this._=this.A-m;break c}N=this._=this.A-m;if(N<=this.D){break b}this._--}break a}this._=this.A-b;if(!g(this,1,'ü')){return false}b:while(true){n=this.A-this._;D=true;c:while(D===true){D=false;if(!f(this,a.g_vowel6,246,252)){break c}this._=this.A-n;break b}F=this._=this.A-n;if(F<=this.D){return false}this._--}}this._=this.A-E;return true};a.prototype.r_check_vowel_harmony=a.prototype.O;function c(b){var F;var r;var c;var e;var h;var i;var j;var k;var l;var m;var n;var o;var p;var q;var d;var s;var t;var u;var v;var w;var x;var y;var z;var A;var B;var C;var D;var E;var H;var I;var J;var K;var L;var M;var N;var O;var G;F=b.A-b._;b:while(true){r=b.A-b._;o=true;a:while(o===true){o=false;if(!f(b,a.g_vowel,97,305)){break a}b._=b.A-r;break b}H=b._=b.A-r;if(H<=b.D){return false}b._--}p=true;a:while(p===true){p=false;c=b.A-b._;q=true;b:while(q===true){q=false;if(!g(b,1,'a')){break b}c:while(true){e=b.A-b._;d=true;d:while(d===true){d=false;if(!f(b,a.g_vowel1,97,305)){break d}b._=b.A-e;break c}I=b._=b.A-e;if(I<=b.D){break b}b._--}break a}b._=b.A-c;s=true;b:while(s===true){s=false;if(!g(b,1,'e')){break b}c:while(true){h=b.A-b._;t=true;d:while(t===true){t=false;if(!f(b,a.g_vowel2,101,252)){break d}b._=b.A-h;break c}J=b._=b.A-h;if(J<=b.D){break b}b._--}break a}b._=b.A-c;u=true;b:while(u===true){u=false;if(!g(b,1,'ı')){break b}c:while(true){i=b.A-b._;v=true;d:while(v===true){v=false;if(!f(b,a.g_vowel3,97,305)){break d}b._=b.A-i;break c}K=b._=b.A-i;if(K<=b.D){break b}b._--}break a}b._=b.A-c;w=true;b:while(w===true){w=false;if(!g(b,1,'i')){break b}c:while(true){j=b.A-b._;x=true;d:while(x===true){x=false;if(!f(b,a.g_vowel4,101,105)){break d}b._=b.A-j;break c}L=b._=b.A-j;if(L<=b.D){break b}b._--}break a}b._=b.A-c;y=true;b:while(y===true){y=false;if(!g(b,1,'o')){break b}c:while(true){k=b.A-b._;z=true;d:while(z===true){z=false;if(!f(b,a.g_vowel5,111,117)){break d}b._=b.A-k;break c}M=b._=b.A-k;if(M<=b.D){break b}b._--}break a}b._=b.A-c;A=true;b:while(A===true){A=false;if(!g(b,1,'ö')){break b}c:while(true){l=b.A-b._;B=true;d:while(B===true){B=false;if(!f(b,a.g_vowel6,246,252)){break d}b._=b.A-l;break c}N=b._=b.A-l;if(N<=b.D){break b}b._--}break a}b._=b.A-c;C=true;b:while(C===true){C=false;if(!g(b,1,'u')){break b}c:while(true){m=b.A-b._;D=true;d:while(D===true){D=false;if(!f(b,a.g_vowel5,111,117)){break d}b._=b.A-m;break c}O=b._=b.A-m;if(O<=b.D){break b}b._--}break a}b._=b.A-c;if(!g(b,1,'ü')){return false}b:while(true){n=b.A-b._;E=true;c:while(E===true){E=false;if(!f(b,a.g_vowel6,246,252)){break c}b._=b.A-n;break b}G=b._=b.A-n;if(G<=b.D){return false}b._--}}b._=b.A-F;return true};a.prototype.j=function(){var k;var h;var l;var i;var m;var j;var b;var e;var d;var n;var o;var p;var q;var c;b=true;b:while(b===true){b=false;k=this.A-this._;e=true;a:while(e===true){e=false;h=this.A-this._;if(!g(this,1,'n')){break a}n=this._=this.A-h;if(n<=this.D){break a}this._--;l=this.A-this._;if(!f(this,a.g_vowel,97,305)){break a}this._=this.A-l;break b}p=this._=(o=this.A)-k;i=o-p;d=true;a:while(d===true){d=false;m=this.A-this._;if(!g(this,1,'n')){break a}this._=this.A-m;return false}c=this._=(q=this.A)-i;j=q-c;if(c<=this.D){return false}this._--;if(!f(this,a.g_vowel,97,305)){return false}this._=this.A-j}return true};a.prototype.r_mark_suffix_with_optional_n_consonant=a.prototype.j;function o(b){var i;var m;var l;var j;var n;var k;var c;var e;var d;var o;var p;var q;var r;var h;c=true;b:while(c===true){c=false;i=b.A-b._;e=true;a:while(e===true){e=false;m=b.A-b._;if(!g(b,1,'n')){break a}o=b._=b.A-m;if(o<=b.D){break a}b._--;l=b.A-b._;if(!f(b,a.g_vowel,97,305)){break a}b._=b.A-l;break b}q=b._=(p=b.A)-i;j=p-q;d=true;a:while(d===true){d=false;n=b.A-b._;if(!g(b,1,'n')){break a}b._=b.A-n;return false}h=b._=(r=b.A)-j;k=r-h;if(h<=b.D){return false}b._--;if(!f(b,a.g_vowel,97,305)){return false}b._=b.A-k}return true};a.prototype.k=function(){var k;var h;var l;var i;var m;var j;var b;var e;var d;var n;var o;var p;var q;var c;b=true;b:while(b===true){b=false;k=this.A-this._;e=true;a:while(e===true){e=false;h=this.A-this._;if(!g(this,1,'s')){break a}n=this._=this.A-h;if(n<=this.D){break a}this._--;l=this.A-this._;if(!f(this,a.g_vowel,97,305)){break a}this._=this.A-l;break b}p=this._=(o=this.A)-k;i=o-p;d=true;a:while(d===true){d=false;m=this.A-this._;if(!g(this,1,'s')){break a}this._=this.A-m;return false}c=this._=(q=this.A)-i;j=q-c;if(c<=this.D){return false}this._--;if(!f(this,a.g_vowel,97,305)){return false}this._=this.A-j}return true};a.prototype.r_mark_suffix_with_optional_s_consonant=a.prototype.k;function l(b){var i;var m;var l;var j;var n;var k;var c;var e;var d;var o;var p;var q;var r;var h;c=true;b:while(c===true){c=false;i=b.A-b._;e=true;a:while(e===true){e=false;m=b.A-b._;if(!g(b,1,'s')){break a}o=b._=b.A-m;if(o<=b.D){break a}b._--;l=b.A-b._;if(!f(b,a.g_vowel,97,305)){break a}b._=b.A-l;break b}q=b._=(p=b.A)-i;j=p-q;d=true;a:while(d===true){d=false;n=b.A-b._;if(!g(b,1,'s')){break a}b._=b.A-n;return false}h=b._=(r=b.A)-j;k=r-h;if(h<=b.D){return false}b._--;if(!f(b,a.g_vowel,97,305)){return false}b._=b.A-k}return true};a.prototype.l=function(){var k;var h;var l;var i;var m;var j;var b;var e;var d;var n;var o;var p;var q;var c;b=true;b:while(b===true){b=false;k=this.A-this._;e=true;a:while(e===true){e=false;h=this.A-this._;if(!g(this,1,'y')){break a}n=this._=this.A-h;if(n<=this.D){break a}this._--;l=this.A-this._;if(!f(this,a.g_vowel,97,305)){break a}this._=this.A-l;break b}p=this._=(o=this.A)-k;i=o-p;d=true;a:while(d===true){d=false;m=this.A-this._;if(!g(this,1,'y')){break a}this._=this.A-m;return false}c=this._=(q=this.A)-i;j=q-c;if(c<=this.D){return false}this._--;if(!f(this,a.g_vowel,97,305)){return false}this._=this.A-j}return true};a.prototype.r_mark_suffix_with_optional_y_consonant=a.prototype.l;function h(b){var i;var m;var l;var j;var n;var k;var c;var e;var d;var o;var p;var q;var r;var h;c=true;b:while(c===true){c=false;i=b.A-b._;e=true;a:while(e===true){e=false;m=b.A-b._;if(!g(b,1,'y')){break a}o=b._=b.A-m;if(o<=b.D){break a}b._--;l=b.A-b._;if(!f(b,a.g_vowel,97,305)){break a}b._=b.A-l;break b}q=b._=(p=b.A)-i;j=p-q;d=true;a:while(d===true){d=false;n=b.A-b._;if(!g(b,1,'y')){break a}b._=b.A-n;return false}h=b._=(r=b.A)-j;k=r-h;if(h<=b.D){return false}b._--;if(!f(b,a.g_vowel,97,305)){return false}b._=b.A-k}return true};a.prototype.i=function(){var j;var g;var k;var h;var l;var i;var b;var e;var d;var m;var n;var o;var p;var c;b=true;b:while(b===true){b=false;j=this.A-this._;e=true;a:while(e===true){e=false;g=this.A-this._;if(!f(this,a.g_U,105,305)){break a}m=this._=this.A-g;if(m<=this.D){break a}this._--;k=this.A-this._;if(!t(this,a.g_vowel,97,305)){break a}this._=this.A-k;break b}o=this._=(n=this.A)-j;h=n-o;d=true;a:while(d===true){d=false;l=this.A-this._;if(!f(this,a.g_U,105,305)){break a}this._=this.A-l;return false}c=this._=(p=this.A)-h;i=p-c;if(c<=this.D){return false}this._--;if(!t(this,a.g_vowel,97,305)){return false}this._=this.A-i}return true};a.prototype.r_mark_suffix_with_optional_U_vowel=a.prototype.i;function k(b){var h;var l;var k;var i;var m;var j;var c;var e;var d;var n;var o;var p;var q;var g;c=true;b:while(c===true){c=false;h=b.A-b._;e=true;a:while(e===true){e=false;l=b.A-b._;if(!f(b,a.g_U,105,305)){break a}n=b._=b.A-l;if(n<=b.D){break a}b._--;k=b.A-b._;if(!t(b,a.g_vowel,97,305)){break a}b._=b.A-k;break b}p=b._=(o=b.A)-h;i=o-p;d=true;a:while(d===true){d=false;m=b.A-b._;if(!f(b,a.g_U,105,305)){break a}b._=b.A-m;return false}g=b._=(q=b.A)-i;j=q-g;if(g<=b.D){return false}b._--;if(!t(b,a.g_vowel,97,305)){return false}b._=b.A-j}return true};a.prototype.e=function(){return b(this,a.a_0,10)===0?false:!k(this)?false:true};a.prototype.r_mark_possessives=a.prototype.e;a.prototype.f=function(){return!c(this)?false:!f(this,a.g_U,105,305)?false:!l(this)?false:true};a.prototype.r_mark_sU=a.prototype.f;a.prototype.W=function(){return b(this,a.a_1,2)===0?false:true};a.prototype.r_mark_lArI=a.prototype.W;a.prototype.o=function(){return!c(this)?false:!f(this,a.g_U,105,305)?false:!h(this)?false:true};a.prototype.r_mark_yU=a.prototype.o;a.prototype.Y=function(){return!c(this)?false:b(this,a.a_2,4)===0?false:true};a.prototype.r_mark_nU=a.prototype.Y;a.prototype.Z=function(){return!c(this)?false:b(this,a.a_3,4)===0?false:!o(this)?false:true};a.prototype.r_mark_nUn=a.prototype.Z;a.prototype.m=function(){return!c(this)?false:b(this,a.a_4,2)===0?false:!h(this)?false:true};a.prototype.r_mark_yA=a.prototype.m;a.prototype.X=function(){return!c(this)?false:b(this,a.a_5,2)===0?false:true};a.prototype.r_mark_nA=a.prototype.X;a.prototype.Q=function(){return!c(this)?false:b(this,a.a_6,4)===0?false:true};a.prototype.r_mark_DA=a.prototype.Q;a.prototype.c=function(){return!c(this)?false:b(this,a.a_7,2)===0?false:true};a.prototype.r_mark_ndA=a.prototype.c;a.prototype.R=function(){return!c(this)?false:b(this,a.a_8,4)===0?false:true};a.prototype.r_mark_DAn=a.prototype.R;a.prototype.d=function(){return!c(this)?false:b(this,a.a_9,2)===0?false:true};a.prototype.r_mark_ndAn=a.prototype.d;a.prototype.s=function(){return!c(this)?false:b(this,a.a_10,2)===0?false:!h(this)?false:true};a.prototype.r_mark_ylA=a.prototype.s;a.prototype.U=function(){return!g(this,2,'ki')?false:true};a.prototype.r_mark_ki=a.prototype.U;a.prototype.b=function(){return!c(this)?false:b(this,a.a_11,2)===0?false:!o(this)?false:true};a.prototype.r_mark_ncA=a.prototype.b;a.prototype.p=function(){return!c(this)?false:b(this,a.a_12,4)===0?false:!h(this)?false:true};a.prototype.r_mark_yUm=a.prototype.p;a.prototype.g=function(){return!c(this)?false:b(this,a.a_13,4)===0?false:true};a.prototype.r_mark_sUn=a.prototype.g;a.prototype.q=function(){return!c(this)?false:b(this,a.a_14,4)===0?false:!h(this)?false:true};a.prototype.r_mark_yUz=a.prototype.q;a.prototype.h=function(){return b(this,a.a_15,4)===0?false:true};a.prototype.r_mark_sUnUz=a.prototype.h;a.prototype.V=function(){return!c(this)?false:b(this,a.a_16,2)===0?false:true};a.prototype.r_mark_lAr=a.prototype.V;a.prototype.a=function(){return!c(this)?false:b(this,a.a_17,4)===0?false:true};a.prototype.r_mark_nUz=a.prototype.a;a.prototype.S=function(){return!c(this)?false:b(this,a.a_18,8)===0?false:true};a.prototype.r_mark_DUr=a.prototype.S;a.prototype.T=function(){return b(this,a.a_19,2)===0?false:true};a.prototype.r_mark_cAsInA=a.prototype.T;a.prototype.n=function(){return!c(this)?false:b(this,a.a_20,32)===0?false:!h(this)?false:true};a.prototype.r_mark_yDU=a.prototype.n;a.prototype.u=function(){return b(this,a.a_21,8)===0?false:!h(this)?false:true};a.prototype.r_mark_ysA=a.prototype.u;a.prototype.t=function(){return!c(this)?false:b(this,a.a_22,4)===0?false:!h(this)?false:true};a.prototype.r_mark_ymUs_=a.prototype.t;a.prototype.r=function(){return!g(this,3,'ken')?false:!h(this)?false:true};a.prototype.r_mark_yken=a.prototype.r;a.prototype.y=function(){var i;var j;var d;var Y;var k;var X;var l;var W;var V;var f;var r;var s;var t;var u;var v;var w;var x;var y;var z;var A;var B;var C;var m;var E;var F;var G;var H;var I;var J;var K;var L;var M;var N;var O;var P;var Q;var R;var S;var T;var U;var p;var o;var D;var n;var q;this.C=this._;this.B_continue_stemming_noun_suffixes=true;r=true;a:while(r===true){r=false;i=this.A-this._;s=true;d:while(s===true){s=false;t=true;b:while(t===true){t=false;j=this.A-this._;u=true;c:while(u===true){u=false;if(!(!c(this)?false:b(this,a.a_22,4)===0?false:!h(this)?false:true)){break c}break b}this._=this.A-j;v=true;c:while(v===true){v=false;if(!(!c(this)?false:b(this,a.a_20,32)===0?false:!h(this)?false:true)){break c}break b}this._=this.A-j;w=true;c:while(w===true){w=false;if(!(b(this,a.a_21,8)===0?false:!h(this)?false:true)){break c}break b}this._=this.A-j;if(!(!g(this,3,'ken')?false:!h(this)?false:true)){break d}}break a}this._=this.A-i;x=true;c:while(x===true){x=false;if(!(b(this,a.a_19,2)===0?false:true)){break c}y=true;b:while(y===true){y=false;d=this.A-this._;z=true;d:while(z===true){z=false;if(!(b(this,a.a_15,4)===0?false:true)){break d}break b}this._=this.A-d;A=true;d:while(A===true){A=false;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){break d}break b}this._=this.A-d;B=true;d:while(B===true){B=false;if(!(!c(this)?false:b(this,a.a_12,4)===0?false:!h(this)?false:true)){break d}break b}this._=this.A-d;C=true;d:while(C===true){C=false;if(!(!c(this)?false:b(this,a.a_13,4)===0?false:true)){break d}break b}this._=this.A-d;m=true;d:while(m===true){m=false;if(!(!c(this)?false:b(this,a.a_14,4)===0?false:!h(this)?false:true)){break d}break b}this._=this.A-d}if(!(!c(this)?false:b(this,a.a_22,4)===0?false:!h(this)?false:true)){break c}break a}this._=this.A-i;E=true;c:while(E===true){E=false;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){break c}this.B=this._;if(!e(this,'')){return false}Y=this.A-this._;F=true;d:while(F===true){F=false;this.C=this._;G=true;b:while(G===true){G=false;k=this.A-this._;H=true;e:while(H===true){H=false;if(!(!c(this)?false:b(this,a.a_18,8)===0?false:true)){break e}break b}this._=this.A-k;I=true;e:while(I===true){I=false;if(!(!c(this)?false:b(this,a.a_20,32)===0?false:!h(this)?false:true)){break e}break b}this._=this.A-k;J=true;e:while(J===true){J=false;if(!(b(this,a.a_21,8)===0?false:!h(this)?false:true)){break e}break b}this._=this.A-k;if(!(!c(this)?false:b(this,a.a_22,4)===0?false:!h(this)?false:true)){this._=this.A-Y;break d}}}this.B_continue_stemming_noun_suffixes=false;break a}this._=this.A-i;K=true;b:while(K===true){K=false;if(!(!c(this)?false:b(this,a.a_17,4)===0?false:true)){break b}L=true;c:while(L===true){L=false;X=this.A-this._;M=true;d:while(M===true){M=false;if(!(!c(this)?false:b(this,a.a_20,32)===0?false:!h(this)?false:true)){break d}break c}this._=this.A-X;if(!(b(this,a.a_21,8)===0?false:!h(this)?false:true)){break b}}break a}this._=this.A-i;N=true;c:while(N===true){N=false;O=true;b:while(O===true){O=false;l=this.A-this._;P=true;d:while(P===true){P=false;if(!(b(this,a.a_15,4)===0?false:true)){break d}break b}this._=this.A-l;Q=true;d:while(Q===true){Q=false;if(!(!c(this)?false:b(this,a.a_14,4)===0?false:!h(this)?false:true)){break d}break b}this._=this.A-l;R=true;d:while(R===true){R=false;if(!(!c(this)?false:b(this,a.a_13,4)===0?false:true)){break d}break b}this._=this.A-l;if(!(!c(this)?false:b(this,a.a_12,4)===0?false:!h(this)?false:true)){break c}}this.B=this._;if(!e(this,'')){return false}W=this.A-this._;S=true;b:while(S===true){S=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_22,4)===0?false:!h(this)?false:true)){this._=this.A-W;break b}}break a}this._=this.A-i;if(!(!c(this)?false:b(this,a.a_18,8)===0?false:true)){return false}this.B=this._;if(!e(this,'')){return false}V=this.A-this._;T=true;d:while(T===true){T=false;this.C=this._;U=true;b:while(U===true){U=false;f=this.A-this._;p=true;c:while(p===true){p=false;if(!(b(this,a.a_15,4)===0?false:true)){break c}break b}this._=this.A-f;o=true;c:while(o===true){o=false;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){break c}break b}this._=this.A-f;D=true;c:while(D===true){D=false;if(!(!c(this)?false:b(this,a.a_12,4)===0?false:!h(this)?false:true)){break c}break b}this._=this.A-f;n=true;c:while(n===true){n=false;if(!(!c(this)?false:b(this,a.a_13,4)===0?false:true)){break c}break b}this._=this.A-f;q=true;c:while(q===true){q=false;if(!(!c(this)?false:b(this,a.a_14,4)===0?false:!h(this)?false:true)){break c}break b}this._=this.A-f}if(!(!c(this)?false:b(this,a.a_22,4)===0?false:!h(this)?false:true)){this._=this.A-V;break d}}}this.B=this._;return!e(this,'')?false:true};a.prototype.r_stem_nominal_verb_suffixes=a.prototype.y;function J(d){var f;var k;var i;var Z;var l;var Y;var m;var X;var W;var j;var s;var t;var u;var v;var w;var x;var y;var z;var A;var B;var C;var n;var E;var F;var G;var H;var I;var J;var K;var L;var M;var N;var O;var P;var Q;var R;var S;var T;var U;var V;var q;var p;var D;var o;var r;d.C=d._;d.B_continue_stemming_noun_suffixes=true;s=true;a:while(s===true){s=false;f=d.A-d._;t=true;d:while(t===true){t=false;u=true;b:while(u===true){u=false;k=d.A-d._;v=true;c:while(v===true){v=false;if(!(!c(d)?false:b(d,a.a_22,4)===0?false:!h(d)?false:true)){break c}break b}d._=d.A-k;w=true;c:while(w===true){w=false;if(!(!c(d)?false:b(d,a.a_20,32)===0?false:!h(d)?false:true)){break c}break b}d._=d.A-k;x=true;c:while(x===true){x=false;if(!(b(d,a.a_21,8)===0?false:!h(d)?false:true)){break c}break b}d._=d.A-k;if(!(!g(d,3,'ken')?false:!h(d)?false:true)){break d}}break a}d._=d.A-f;y=true;c:while(y===true){y=false;if(!(b(d,a.a_19,2)===0?false:true)){break c}z=true;b:while(z===true){z=false;i=d.A-d._;A=true;d:while(A===true){A=false;if(!(b(d,a.a_15,4)===0?false:true)){break d}break b}d._=d.A-i;B=true;d:while(B===true){B=false;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){break d}break b}d._=d.A-i;C=true;d:while(C===true){C=false;if(!(!c(d)?false:b(d,a.a_12,4)===0?false:!h(d)?false:true)){break d}break b}d._=d.A-i;n=true;d:while(n===true){n=false;if(!(!c(d)?false:b(d,a.a_13,4)===0?false:true)){break d}break b}d._=d.A-i;E=true;d:while(E===true){E=false;if(!(!c(d)?false:b(d,a.a_14,4)===0?false:!h(d)?false:true)){break d}break b}d._=d.A-i}if(!(!c(d)?false:b(d,a.a_22,4)===0?false:!h(d)?false:true)){break c}break a}d._=d.A-f;F=true;c:while(F===true){F=false;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){break c}d.B=d._;if(!e(d,'')){return false}Z=d.A-d._;G=true;d:while(G===true){G=false;d.C=d._;H=true;b:while(H===true){H=false;l=d.A-d._;I=true;e:while(I===true){I=false;if(!(!c(d)?false:b(d,a.a_18,8)===0?false:true)){break e}break b}d._=d.A-l;J=true;e:while(J===true){J=false;if(!(!c(d)?false:b(d,a.a_20,32)===0?false:!h(d)?false:true)){break e}break b}d._=d.A-l;K=true;e:while(K===true){K=false;if(!(b(d,a.a_21,8)===0?false:!h(d)?false:true)){break e}break b}d._=d.A-l;if(!(!c(d)?false:b(d,a.a_22,4)===0?false:!h(d)?false:true)){d._=d.A-Z;break d}}}d.B_continue_stemming_noun_suffixes=false;break a}d._=d.A-f;L=true;b:while(L===true){L=false;if(!(!c(d)?false:b(d,a.a_17,4)===0?false:true)){break b}M=true;c:while(M===true){M=false;Y=d.A-d._;N=true;d:while(N===true){N=false;if(!(!c(d)?false:b(d,a.a_20,32)===0?false:!h(d)?false:true)){break d}break c}d._=d.A-Y;if(!(b(d,a.a_21,8)===0?false:!h(d)?false:true)){break b}}break a}d._=d.A-f;O=true;c:while(O===true){O=false;P=true;b:while(P===true){P=false;m=d.A-d._;Q=true;d:while(Q===true){Q=false;if(!(b(d,a.a_15,4)===0?false:true)){break d}break b}d._=d.A-m;R=true;d:while(R===true){R=false;if(!(!c(d)?false:b(d,a.a_14,4)===0?false:!h(d)?false:true)){break d}break b}d._=d.A-m;S=true;d:while(S===true){S=false;if(!(!c(d)?false:b(d,a.a_13,4)===0?false:true)){break d}break b}d._=d.A-m;if(!(!c(d)?false:b(d,a.a_12,4)===0?false:!h(d)?false:true)){break c}}d.B=d._;if(!e(d,'')){return false}X=d.A-d._;T=true;b:while(T===true){T=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_22,4)===0?false:!h(d)?false:true)){d._=d.A-X;break b}}break a}d._=d.A-f;if(!(!c(d)?false:b(d,a.a_18,8)===0?false:true)){return false}d.B=d._;if(!e(d,'')){return false}W=d.A-d._;U=true;d:while(U===true){U=false;d.C=d._;V=true;b:while(V===true){V=false;j=d.A-d._;q=true;c:while(q===true){q=false;if(!(b(d,a.a_15,4)===0?false:true)){break c}break b}d._=d.A-j;p=true;c:while(p===true){p=false;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){break c}break b}d._=d.A-j;D=true;c:while(D===true){D=false;if(!(!c(d)?false:b(d,a.a_12,4)===0?false:!h(d)?false:true)){break c}break b}d._=d.A-j;o=true;c:while(o===true){o=false;if(!(!c(d)?false:b(d,a.a_13,4)===0?false:true)){break c}break b}d._=d.A-j;r=true;c:while(r===true){r=false;if(!(!c(d)?false:b(d,a.a_14,4)===0?false:!h(d)?false:true)){break c}break b}d._=d.A-j}if(!(!c(d)?false:b(d,a.a_22,4)===0?false:!h(d)?false:true)){d._=d.A-W;break d}}}d.B=d._;return!e(d,'')?false:true};a.prototype.__=function(){var z;var N;var M;var L;var p;var K;var r;var J;var t;var u;var v;var w;var x;var y;var d;var A;var B;var C;var D;var E;var F;var G;var H;var I;var s;var q;var n;var m;var j;var h;this.C=this._;if(!(!g(this,2,'ki')?false:true)){return false}w=true;b:while(w===true){w=false;z=this.A-this._;x=true;c:while(x===true){x=false;if(!(!c(this)?false:b(this,a.a_6,4)===0?false:true)){break c}this.B=this._;if(!e(this,'')){return false}N=this.A-this._;y=true;f:while(y===true){y=false;this.C=this._;d=true;e:while(d===true){d=false;M=this.A-this._;A=true;d:while(A===true){A=false;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){break d}this.B=this._;if(!e(this,'')){return false}L=this.A-this._;B=true;a:while(B===true){B=false;if(!i(this)){this._=this.A-L;break a}}break e}this._=this.A-M;if(!(b(this,a.a_0,10)===0?false:!k(this)?false:true)){this._=this.A-N;break f}this.B=this._;if(!e(this,'')){return false}p=this.A-this._;C=true;a:while(C===true){C=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-p;break a}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-p;break a}}}}break b}this._=this.A-z;D=true;d:while(D===true){D=false;if(!(!c(this)?false:b(this,a.a_3,4)===0?false:!o(this)?false:true)){break d}this.B=this._;if(!e(this,'')){return false}K=this.A-this._;E=true;e:while(E===true){E=false;this.C=this._;F=true;a:while(F===true){F=false;r=this.A-this._;G=true;c:while(G===true){G=false;if(!(b(this,a.a_1,2)===0?false:true)){break c}this.B=this._;if(!e(this,'')){return false}break a}this._=this.A-r;H=true;f:while(H===true){H=false;this.C=this._;I=true;g:while(I===true){I=false;J=this.A-this._;s=true;c:while(s===true){s=false;if(!(b(this,a.a_0,10)===0?false:!k(this)?false:true)){break c}break g}this._=this.A-J;if(!(!c(this)?false:!f(this,a.g_U,105,305)?false:!l(this)?false:true)){break f}}this.B=this._;if(!e(this,'')){return false}t=this.A-this._;q=true;c:while(q===true){q=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-t;break c}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-t;break c}}break a}this._=this.A-r;if(!i(this)){this._=this.A-K;break e}}}break b}this._=this.A-z;if(!(!c(this)?false:b(this,a.a_7,2)===0?false:true)){return false}n=true;a:while(n===true){n=false;u=this.A-this._;m=true;c:while(m===true){m=false;if(!(b(this,a.a_1,2)===0?false:true)){break c}this.B=this._;if(!e(this,'')){return false}break a}this._=this.A-u;j=true;d:while(j===true){j=false;if(!(!c(this)?false:!f(this,a.g_U,105,305)?false:!l(this)?false:true)){break d}this.B=this._;if(!e(this,'')){return false}v=this.A-this._;h=true;c:while(h===true){h=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-v;break c}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-v;break c}}break a}this._=this.A-u;if(!i(this)){return false}}}return true};a.prototype.r_stem_suffix_chain_before_ki=a.prototype.__;function i(d){var j;var O;var N;var M;var q;var L;var s;var K;var u;var v;var w;var x;var y;var z;var h;var B;var C;var D;var E;var F;var G;var H;var I;var J;var t;var r;var p;var n;var m;var A;d.C=d._;if(!(!g(d,2,'ki')?false:true)){return false}x=true;b:while(x===true){x=false;j=d.A-d._;y=true;c:while(y===true){y=false;if(!(!c(d)?false:b(d,a.a_6,4)===0?false:true)){break c}d.B=d._;if(!e(d,'')){return false}O=d.A-d._;z=true;f:while(z===true){z=false;d.C=d._;h=true;e:while(h===true){h=false;N=d.A-d._;B=true;d:while(B===true){B=false;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){break d}d.B=d._;if(!e(d,'')){return false}M=d.A-d._;C=true;a:while(C===true){C=false;if(!i(d)){d._=d.A-M;break a}}break e}d._=d.A-N;if(!(b(d,a.a_0,10)===0?false:!k(d)?false:true)){d._=d.A-O;break f}d.B=d._;if(!e(d,'')){return false}q=d.A-d._;D=true;a:while(D===true){D=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-q;break a}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-q;break a}}}}break b}d._=d.A-j;E=true;d:while(E===true){E=false;if(!(!c(d)?false:b(d,a.a_3,4)===0?false:!o(d)?false:true)){break d}d.B=d._;if(!e(d,'')){return false}L=d.A-d._;F=true;e:while(F===true){F=false;d.C=d._;G=true;a:while(G===true){G=false;s=d.A-d._;H=true;c:while(H===true){H=false;if(!(b(d,a.a_1,2)===0?false:true)){break c}d.B=d._;if(!e(d,'')){return false}break a}d._=d.A-s;I=true;f:while(I===true){I=false;d.C=d._;J=true;g:while(J===true){J=false;K=d.A-d._;t=true;c:while(t===true){t=false;if(!(b(d,a.a_0,10)===0?false:!k(d)?false:true)){break c}break g}d._=d.A-K;if(!(!c(d)?false:!f(d,a.g_U,105,305)?false:!l(d)?false:true)){break f}}d.B=d._;if(!e(d,'')){return false}u=d.A-d._;r=true;c:while(r===true){r=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-u;break c}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-u;break c}}break a}d._=d.A-s;if(!i(d)){d._=d.A-L;break e}}}break b}d._=d.A-j;if(!(!c(d)?false:b(d,a.a_7,2)===0?false:true)){return false}p=true;a:while(p===true){p=false;v=d.A-d._;n=true;c:while(n===true){n=false;if(!(b(d,a.a_1,2)===0?false:true)){break c}d.B=d._;if(!e(d,'')){return false}break a}d._=d.A-v;m=true;d:while(m===true){m=false;if(!(!c(d)?false:!f(d,a.g_U,105,305)?false:!l(d)?false:true)){break d}d.B=d._;if(!e(d,'')){return false}w=d.A-d._;A=true;c:while(A===true){A=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-w;break c}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-w;break c}}break a}d._=d.A-v;if(!i(d)){return false}}}return true};a.prototype.z=function(){var d;var ar;var S;var j;var av;var m;var aq;var n;var p;var ax;var ay;var q;var ap;var r;var s;var as;var at;var au;var t;var aw;var u;var v;var w;var aA;var aB;var ao;var x;var y;var z;var A;var B;var C;var D;var E;var F;var G;var H;var I;var J;var K;var L;var M;var N;var O;var P;var Q;var R;var g;var T;var U;var V;var W;var X;var Y;var Z;var _;var $;var a0;var a1;var a2;var a3;var a4;var a5;var a6;var a7;var a8;var a9;var aa;var ab;var ac;var ad;var ae;var af;var ag;var ah;var ai;var aj;var ak;var al;var am;var an;var aC;var az;y=true;a:while(y===true){y=false;d=this.A-this._;z=true;b:while(z===true){z=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){break b}this.B=this._;if(!e(this,'')){return false}ar=this.A-this._;A=true;c:while(A===true){A=false;if(!i(this)){this._=this.A-ar;break c}}break a}this._=this.A-d;B=true;g:while(B===true){B=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_11,2)===0?false:!o(this)?false:true)){break g}this.B=this._;if(!e(this,'')){return false}S=this.A-this._;C=true;b:while(C===true){C=false;D=true;c:while(D===true){D=false;j=this.A-this._;E=true;d:while(E===true){E=false;this.C=this._;if(!(b(this,a.a_1,2)===0?false:true)){break d}this.B=this._;if(!e(this,'')){return false}break c}this._=this.A-j;F=true;f:while(F===true){F=false;this.C=this._;G=true;d:while(G===true){G=false;av=this.A-this._;H=true;e:while(H===true){H=false;if(!(b(this,a.a_0,10)===0?false:!k(this)?false:true)){break e}break d}this._=this.A-av;if(!(!c(this)?false:!f(this,a.g_U,105,305)?false:!l(this)?false:true)){break f}}this.B=this._;if(!e(this,'')){return false}m=this.A-this._;I=true;d:while(I===true){I=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-m;break d}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-m;break d}}break c}aC=this._=this.A-j;this.C=aC;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-S;break b}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-S;break b}}}break a}this._=this.A-d;J=true;b:while(J===true){J=false;this.C=this._;K=true;d:while(K===true){K=false;aq=this.A-this._;L=true;c:while(L===true){L=false;if(!(!c(this)?false:b(this,a.a_7,2)===0?false:true)){break c}break d}this._=this.A-aq;if(!(!c(this)?false:b(this,a.a_5,2)===0?false:true)){break b}}M=true;c:while(M===true){M=false;n=this.A-this._;N=true;d:while(N===true){N=false;if(!(b(this,a.a_1,2)===0?false:true)){break d}this.B=this._;if(!e(this,'')){return false}break c}this._=this.A-n;O=true;e:while(O===true){O=false;if(!(!c(this)?false:!f(this,a.g_U,105,305)?false:!l(this)?false:true)){break e}this.B=this._;if(!e(this,'')){return false}p=this.A-this._;P=true;d:while(P===true){P=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-p;break d}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-p;break d}}break c}this._=this.A-n;if(!i(this)){break b}}break a}this._=this.A-d;Q=true;c:while(Q===true){Q=false;this.C=this._;R=true;b:while(R===true){R=false;ax=this.A-this._;g=true;d:while(g===true){g=false;if(!(!c(this)?false:b(this,a.a_9,2)===0?false:true)){break d}break b}this._=this.A-ax;if(!(!c(this)?false:b(this,a.a_2,4)===0?false:true)){break c}}T=true;d:while(T===true){T=false;ay=this.A-this._;U=true;e:while(U===true){U=false;if(!(!c(this)?false:!f(this,a.g_U,105,305)?false:!l(this)?false:true)){break e}this.B=this._;if(!e(this,'')){return false}q=this.A-this._;V=true;b:while(V===true){V=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-q;break b}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-q;break b}}break d}this._=this.A-ay;if(!(b(this,a.a_1,2)===0?false:true)){break c}}break a}this._=this.A-d;W=true;d:while(W===true){W=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_8,4)===0?false:true)){break d}this.B=this._;if(!e(this,'')){return false}ap=this.A-this._;X=true;e:while(X===true){X=false;this.C=this._;Y=true;c:while(Y===true){Y=false;r=this.A-this._;Z=true;f:while(Z===true){Z=false;if(!(b(this,a.a_0,10)===0?false:!k(this)?false:true)){break f}this.B=this._;if(!e(this,'')){return false}s=this.A-this._;_=true;b:while(_===true){_=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-s;break b}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-s;break b}}break c}this._=this.A-r;$=true;b:while($===true){$=false;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){break b}this.B=this._;if(!e(this,'')){return false}as=this.A-this._;a0=true;f:while(a0===true){a0=false;if(!i(this)){this._=this.A-as;break f}}break c}this._=this.A-r;if(!i(this)){this._=this.A-ap;break e}}}break a}this._=this.A-d;a1=true;d:while(a1===true){a1=false;this.C=this._;a2=true;b:while(a2===true){a2=false;at=this.A-this._;a3=true;c:while(a3===true){a3=false;if(!(!c(this)?false:b(this,a.a_3,4)===0?false:!o(this)?false:true)){break c}break b}this._=this.A-at;if(!(!c(this)?false:b(this,a.a_10,2)===0?false:!h(this)?false:true)){break d}}this.B=this._;if(!e(this,'')){return false}au=this.A-this._;a4=true;e:while(a4===true){a4=false;a5=true;c:while(a5===true){a5=false;t=this.A-this._;a6=true;b:while(a6===true){a6=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){break b}this.B=this._;if(!e(this,'')){return false}if(!i(this)){break b}break c}this._=this.A-t;a7=true;f:while(a7===true){a7=false;this.C=this._;a8=true;b:while(a8===true){a8=false;aw=this.A-this._;a9=true;g:while(a9===true){a9=false;if(!(b(this,a.a_0,10)===0?false:!k(this)?false:true)){break g}break b}this._=this.A-aw;if(!(!c(this)?false:!f(this,a.g_U,105,305)?false:!l(this)?false:true)){break f}}this.B=this._;if(!e(this,'')){return false}u=this.A-this._;aa=true;b:while(aa===true){aa=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-u;break b}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-u;break b}}break c}this._=this.A-t;if(!i(this)){this._=this.A-au;break e}}}break a}this._=this.A-d;ab=true;b:while(ab===true){ab=false;this.C=this._;if(!(b(this,a.a_1,2)===0?false:true)){break b}this.B=this._;if(!e(this,'')){return false}break a}this._=this.A-d;ac=true;b:while(ac===true){ac=false;if(!i(this)){break b}break a}this._=this.A-d;ad=true;c:while(ad===true){ad=false;this.C=this._;ae=true;b:while(ae===true){ae=false;v=this.A-this._;af=true;d:while(af===true){af=false;if(!(!c(this)?false:b(this,a.a_6,4)===0?false:true)){break d}break b}this._=this.A-v;ag=true;d:while(ag===true){ag=false;if(!(!c(this)?false:!f(this,a.g_U,105,305)?false:!h(this)?false:true)){break d}break b}this._=this.A-v;if(!(!c(this)?false:b(this,a.a_4,2)===0?false:!h(this)?false:true)){break c}}this.B=this._;if(!e(this,'')){return false}w=this.A-this._;ah=true;b:while(ah===true){ah=false;this.C=this._;ai=true;d:while(ai===true){ai=false;aA=this.A-this._;aj=true;e:while(aj===true){aj=false;if(!(b(this,a.a_0,10)===0?false:!k(this)?false:true)){break e}this.B=this._;if(!e(this,'')){return false}aB=this.A-this._;ak=true;f:while(ak===true){ak=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-aB;break f}}break d}this._=this.A-aA;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-w;break b}}this.B=this._;if(!e(this,'')){return false}this.C=this._;if(!i(this)){this._=this.A-w;break b}}break a}az=this._=this.A-d;this.C=az;al=true;b:while(al===true){al=false;ao=this.A-this._;am=true;c:while(am===true){am=false;if(!(b(this,a.a_0,10)===0?false:!k(this)?false:true)){break c}break b}this._=this.A-ao;if(!(!c(this)?false:!f(this,a.g_U,105,305)?false:!l(this)?false:true)){return false}}this.B=this._;if(!e(this,'')){return false}x=this.A-this._;an=true;b:while(an===true){an=false;this.C=this._;if(!(!c(this)?false:b(this,a.a_16,2)===0?false:true)){this._=this.A-x;break b}this.B=this._;if(!e(this,'')){return false}if(!i(this)){this._=this.A-x;break b}}}return true};a.prototype.r_stem_noun_suffixes=a.prototype.z;function L(d){var g;var as;var S;var m;var aw;var n;var ar;var p;var q;var ay;var az;var r;var aq;var s;var t;var at;var au;var av;var u;var ax;var v;var w;var x;var aB;var aC;var ap;var y;var z;var A;var B;var C;var D;var E;var F;var G;var H;var I;var J;var K;var L;var M;var N;var O;var P;var Q;var R;var j;var T;var U;var V;var W;var X;var Y;var Z;var _;var $;var a0;var a1;var a2;var a3;var a4;var a5;var a6;var a7;var a8;var a9;var aa;var ab;var ac;var ad;var ae;var af;var ag;var ah;var ai;var aj;var ak;var al;var am;var an;var ao;var aD;var aA;z=true;a:while(z===true){z=false;g=d.A-d._;A=true;b:while(A===true){A=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){break b}d.B=d._;if(!e(d,'')){return false}as=d.A-d._;B=true;c:while(B===true){B=false;if(!i(d)){d._=d.A-as;break c}}break a}d._=d.A-g;C=true;g:while(C===true){C=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_11,2)===0?false:!o(d)?false:true)){break g}d.B=d._;if(!e(d,'')){return false}S=d.A-d._;D=true;b:while(D===true){D=false;E=true;c:while(E===true){E=false;m=d.A-d._;F=true;d:while(F===true){F=false;d.C=d._;if(!(b(d,a.a_1,2)===0?false:true)){break d}d.B=d._;if(!e(d,'')){return false}break c}d._=d.A-m;G=true;f:while(G===true){G=false;d.C=d._;H=true;d:while(H===true){H=false;aw=d.A-d._;I=true;e:while(I===true){I=false;if(!(b(d,a.a_0,10)===0?false:!k(d)?false:true)){break e}break d}d._=d.A-aw;if(!(!c(d)?false:!f(d,a.g_U,105,305)?false:!l(d)?false:true)){break f}}d.B=d._;if(!e(d,'')){return false}n=d.A-d._;J=true;d:while(J===true){J=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-n;break d}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-n;break d}}break c}aD=d._=d.A-m;d.C=aD;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-S;break b}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-S;break b}}}break a}d._=d.A-g;K=true;b:while(K===true){K=false;d.C=d._;L=true;d:while(L===true){L=false;ar=d.A-d._;M=true;c:while(M===true){M=false;if(!(!c(d)?false:b(d,a.a_7,2)===0?false:true)){break c}break d}d._=d.A-ar;if(!(!c(d)?false:b(d,a.a_5,2)===0?false:true)){break b}}N=true;c:while(N===true){N=false;p=d.A-d._;O=true;d:while(O===true){O=false;if(!(b(d,a.a_1,2)===0?false:true)){break d}d.B=d._;if(!e(d,'')){return false}break c}d._=d.A-p;P=true;e:while(P===true){P=false;if(!(!c(d)?false:!f(d,a.g_U,105,305)?false:!l(d)?false:true)){break e}d.B=d._;if(!e(d,'')){return false}q=d.A-d._;Q=true;d:while(Q===true){Q=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-q;break d}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-q;break d}}break c}d._=d.A-p;if(!i(d)){break b}}break a}d._=d.A-g;R=true;c:while(R===true){R=false;d.C=d._;j=true;b:while(j===true){j=false;ay=d.A-d._;T=true;d:while(T===true){T=false;if(!(!c(d)?false:b(d,a.a_9,2)===0?false:true)){break d}break b}d._=d.A-ay;if(!(!c(d)?false:b(d,a.a_2,4)===0?false:true)){break c}}U=true;d:while(U===true){U=false;az=d.A-d._;V=true;e:while(V===true){V=false;if(!(!c(d)?false:!f(d,a.g_U,105,305)?false:!l(d)?false:true)){break e}d.B=d._;if(!e(d,'')){return false}r=d.A-d._;W=true;b:while(W===true){W=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-r;break b}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-r;break b}}break d}d._=d.A-az;if(!(b(d,a.a_1,2)===0?false:true)){break c}}break a}d._=d.A-g;X=true;d:while(X===true){X=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_8,4)===0?false:true)){break d}d.B=d._;if(!e(d,'')){return false}aq=d.A-d._;Y=true;e:while(Y===true){Y=false;d.C=d._;Z=true;c:while(Z===true){Z=false;s=d.A-d._;_=true;f:while(_===true){_=false;if(!(b(d,a.a_0,10)===0?false:!k(d)?false:true)){break f}d.B=d._;if(!e(d,'')){return false}t=d.A-d._;$=true;b:while($===true){$=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-t;break b}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-t;break b}}break c}d._=d.A-s;a0=true;b:while(a0===true){a0=false;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){break b}d.B=d._;if(!e(d,'')){return false}at=d.A-d._;a1=true;f:while(a1===true){a1=false;if(!i(d)){d._=d.A-at;break f}}break c}d._=d.A-s;if(!i(d)){d._=d.A-aq;break e}}}break a}d._=d.A-g;a2=true;d:while(a2===true){a2=false;d.C=d._;a3=true;b:while(a3===true){a3=false;au=d.A-d._;a4=true;c:while(a4===true){a4=false;if(!(!c(d)?false:b(d,a.a_3,4)===0?false:!o(d)?false:true)){break c}break b}d._=d.A-au;if(!(!c(d)?false:b(d,a.a_10,2)===0?false:!h(d)?false:true)){break d}}d.B=d._;if(!e(d,'')){return false}av=d.A-d._;a5=true;e:while(a5===true){a5=false;a6=true;c:while(a6===true){a6=false;u=d.A-d._;a7=true;b:while(a7===true){a7=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){break b}d.B=d._;if(!e(d,'')){return false}if(!i(d)){break b}break c}d._=d.A-u;a8=true;f:while(a8===true){a8=false;d.C=d._;a9=true;b:while(a9===true){a9=false;ax=d.A-d._;aa=true;g:while(aa===true){aa=false;if(!(b(d,a.a_0,10)===0?false:!k(d)?false:true)){break g}break b}d._=d.A-ax;if(!(!c(d)?false:!f(d,a.g_U,105,305)?false:!l(d)?false:true)){break f}}d.B=d._;if(!e(d,'')){return false}v=d.A-d._;ab=true;b:while(ab===true){ab=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-v;break b}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-v;break b}}break c}d._=d.A-u;if(!i(d)){d._=d.A-av;break e}}}break a}d._=d.A-g;ac=true;b:while(ac===true){ac=false;d.C=d._;if(!(b(d,a.a_1,2)===0?false:true)){break b}d.B=d._;if(!e(d,'')){return false}break a}d._=d.A-g;ad=true;b:while(ad===true){ad=false;if(!i(d)){break b}break a}d._=d.A-g;ae=true;c:while(ae===true){ae=false;d.C=d._;af=true;b:while(af===true){af=false;w=d.A-d._;ag=true;d:while(ag===true){ag=false;if(!(!c(d)?false:b(d,a.a_6,4)===0?false:true)){break d}break b}d._=d.A-w;ah=true;d:while(ah===true){ah=false;if(!(!c(d)?false:!f(d,a.g_U,105,305)?false:!h(d)?false:true)){break d}break b}d._=d.A-w;if(!(!c(d)?false:b(d,a.a_4,2)===0?false:!h(d)?false:true)){break c}}d.B=d._;if(!e(d,'')){return false}x=d.A-d._;ai=true;b:while(ai===true){ai=false;d.C=d._;aj=true;d:while(aj===true){aj=false;aB=d.A-d._;ak=true;e:while(ak===true){ak=false;if(!(b(d,a.a_0,10)===0?false:!k(d)?false:true)){break e}d.B=d._;if(!e(d,'')){return false}aC=d.A-d._;al=true;f:while(al===true){al=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-aC;break f}}break d}d._=d.A-aB;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-x;break b}}d.B=d._;if(!e(d,'')){return false}d.C=d._;if(!i(d)){d._=d.A-x;break b}}break a}aA=d._=d.A-g;d.C=aA;am=true;b:while(am===true){am=false;ap=d.A-d._;an=true;c:while(an===true){an=false;if(!(b(d,a.a_0,10)===0?false:!k(d)?false:true)){break c}break b}d._=d.A-ap;if(!(!c(d)?false:!f(d,a.g_U,105,305)?false:!l(d)?false:true)){return false}}d.B=d._;if(!e(d,'')){return false}y=d.A-d._;ao=true;b:while(ao===true){ao=false;d.C=d._;if(!(!c(d)?false:b(d,a.a_16,2)===0?false:true)){d._=d.A-y;break b}d.B=d._;if(!e(d,'')){return false}if(!i(d)){d._=d.A-y;break b}}}return true};a.prototype.w=function(){var c;this.C=this._;c=b(this,a.a_23,4);if(c===0){return false}this.B=this._;switch(c){case 0:return false;case 1:if(!e(this,'p')){return false}break;case 2:if(!e(this,'ç')){return false}break;case 3:if(!e(this,'t')){return false}break;case 4:if(!e(this,'k')){return false}break}return true};a.prototype.r_post_process_last_consonants=a.prototype.w;function w(c){var d;c.C=c._;d=b(c,a.a_23,4);if(d===0){return false}c.B=c._;switch(d){case 0:return false;case 1:if(!e(c,'p')){return false}break;case 2:if(!e(c,'ç')){return false}break;case 3:if(!e(c,'t')){return false}break;case 4:if(!e(c,'k')){return false}break}return true};a.prototype.N=function(){var L;var _;var i;var Y;var B;var W;var K;var l;var S;var Q;var p;var O;var M;var s;var U;var u;var v;var w;var x;var y;var z;var A;var b;var C;var D;var j;var F;var G;var H;var I;var J;var E;var t;var r;var N;var q;var P;var o;var R;var m;var T;var k;var V;var h;var X;var e;var Z;var d;var $;var a0;var a1;var c;L=this.A-this._;u=true;a:while(u===true){u=false;_=this.A-this._;v=true;b:while(v===true){v=false;if(!g(this,1,'d')){break b}break a}this._=this.A-_;if(!g(this,1,'g')){return false}}this._=this.A-L;w=true;a:while(w===true){w=false;i=this.A-this._;x=true;b:while(x===true){x=false;Y=this.A-this._;d:while(true){B=this.A-this._;y=true;c:while(y===true){y=false;if(!f(this,a.g_vowel,97,305)){break c}this._=this.A-B;break d}V=this._=this.A-B;if(V<=this.D){break b}this._--}z=true;c:while(z===true){z=false;W=this.A-this._;A=true;d:while(A===true){A=false;if(!g(this,1,'a')){break d}break c}this._=this.A-W;if(!g(this,1,'ı')){break b}}h=this._=this.A-Y;b=h;N=h;q=n(this,h,h,'ı');if(h<=this.B){this.B+=q|0}if(N<=this.C){this.C+=q|0}this._=b;break a}this._=this.A-i;C=true;b:while(C===true){C=false;K=this.A-this._;c:while(true){l=this.A-this._;D=true;d:while(D===true){D=false;if(!f(this,a.g_vowel,97,305)){break d}this._=this.A-l;break c}X=this._=this.A-l;if(X<=this.D){break b}this._--}j=true;c:while(j===true){j=false;S=this.A-this._;F=true;d:while(F===true){F=false;if(!g(this,1,'e')){break d}break c}this._=this.A-S;if(!g(this,1,'i')){break b}}e=this._=this.A-K;b=e;P=e;o=n(this,e,e,'i');if(e<=this.B){this.B+=o|0}if(P<=this.C){this.C+=o|0}this._=b;break a}this._=this.A-i;G=true;b:while(G===true){G=false;Q=this.A-this._;c:while(true){p=this.A-this._;H=true;d:while(H===true){H=false;if(!f(this,a.g_vowel,97,305)){break d}this._=this.A-p;break c}Z=this._=this.A-p;if(Z<=this.D){break b}this._--}I=true;c:while(I===true){I=false;O=this.A-this._;J=true;d:while(J===true){J=false;if(!g(this,1,'o')){break d}break c}this._=this.A-O;if(!g(this,1,'u')){break b}}d=this._=this.A-Q;b=d;R=d;m=n(this,d,d,'u');if(d<=this.B){this.B+=m|0}if(R<=this.C){this.C+=m|0}this._=b;break a}a1=this._=(a0=this.A)-i;M=a0-a1;b:while(true){s=this.A-this._;E=true;c:while(E===true){E=false;if(!f(this,a.g_vowel,97,305)){break c}this._=this.A-s;break b}$=this._=this.A-s;if($<=this.D){return false}this._--}t=true;b:while(t===true){t=false;U=this.A-this._;r=true;c:while(r===true){r=false;if(!g(this,1,'ö')){break c}break b}this._=this.A-U;if(!g(this,1,'ü')){return false}}c=this._=this.A-M;b=c;T=c;k=n(this,c,c,'ü');if(c<=this.B){this.B+=k|0}if(T<=this.C){this.C+=k|0}this._=b}return true};a.prototype.r_append_U_to_stems_ending_with_d_or_g=a.prototype.N;function z(b){var $;var Z;var j;var X;var F;var L;var T;var m;var R;var P;var q;var N;var V;var t;var M;var v;var w;var x;var y;var z;var A;var B;var c;var D;var E;var C;var G;var H;var I;var J;var K;var u;var s;var r;var O;var p;var Q;var o;var S;var l;var U;var k;var W;var i;var Y;var h;var _;var e;var a0;var a1;var a2;var d;$=b.A-b._;v=true;a:while(v===true){v=false;Z=b.A-b._;w=true;b:while(w===true){w=false;if(!g(b,1,'d')){break b}break a}b._=b.A-Z;if(!g(b,1,'g')){return false}}b._=b.A-$;x=true;a:while(x===true){x=false;j=b.A-b._;y=true;b:while(y===true){y=false;X=b.A-b._;d:while(true){F=b.A-b._;z=true;c:while(z===true){z=false;if(!f(b,a.g_vowel,97,305)){break c}b._=b.A-F;break d}W=b._=b.A-F;if(W<=b.D){break b}b._--}A=true;c:while(A===true){A=false;L=b.A-b._;B=true;d:while(B===true){B=false;if(!g(b,1,'a')){break d}break c}b._=b.A-L;if(!g(b,1,'ı')){break b}}i=b._=b.A-X;c=i;O=i;p=n(b,i,i,'ı');if(i<=b.B){b.B+=p|0}if(O<=b.C){b.C+=p|0}b._=c;break a}b._=b.A-j;D=true;b:while(D===true){D=false;T=b.A-b._;c:while(true){m=b.A-b._;E=true;d:while(E===true){E=false;if(!f(b,a.g_vowel,97,305)){break d}b._=b.A-m;break c}Y=b._=b.A-m;if(Y<=b.D){break b}b._--}C=true;c:while(C===true){C=false;R=b.A-b._;G=true;d:while(G===true){G=false;if(!g(b,1,'e')){break d}break c}b._=b.A-R;if(!g(b,1,'i')){break b}}h=b._=b.A-T;c=h;Q=h;o=n(b,h,h,'i');if(h<=b.B){b.B+=o|0}if(Q<=b.C){b.C+=o|0}b._=c;break a}b._=b.A-j;H=true;b:while(H===true){H=false;P=b.A-b._;c:while(true){q=b.A-b._;I=true;d:while(I===true){I=false;if(!f(b,a.g_vowel,97,305)){break d}b._=b.A-q;break c}_=b._=b.A-q;if(_<=b.D){break b}b._--}J=true;c:while(J===true){J=false;N=b.A-b._;K=true;d:while(K===true){K=false;if(!g(b,1,'o')){break d}break c}b._=b.A-N;if(!g(b,1,'u')){break b}}e=b._=b.A-P;c=e;S=e;l=n(b,e,e,'u');if(e<=b.B){b.B+=l|0}if(S<=b.C){b.C+=l|0}b._=c;break a}a2=b._=(a1=b.A)-j;V=a1-a2;b:while(true){t=b.A-b._;u=true;c:while(u===true){u=false;if(!f(b,a.g_vowel,97,305)){break c}b._=b.A-t;break b}a0=b._=b.A-t;if(a0<=b.D){return false}b._--}s=true;b:while(s===true){s=false;M=b.A-b._;r=true;c:while(r===true){r=false;if(!g(b,1,'ö')){break c}break b}b._=b.A-M;if(!g(b,1,'ü')){return false}}d=b._=b.A-V;c=d;U=d;k=n(b,d,d,'ü');if(d<=b.B){b.B+=k|0}if(U<=b.C){b.C+=k|0}b._=c}return true};a.prototype.v=function(){var e;var f;var b;var c;var d;e=this._;b=2;a:while(true){f=this._;c=true;b:while(c===true){c=false;c:while(true){d=true;d:while(d===true){d=false;if(!v(this,a.g_vowel,97,305)){break d}break c}if(this._>=this.A){break b}this._++}b--;continue a}this._=f;break a}if(b>0){return false}this._=e;return true};a.prototype.r_more_than_one_syllable_word=a.prototype.v;function N(b){var f;var g;var c;var d;var e;f=b._;c=2;a:while(true){g=b._;d=true;b:while(d===true){d=false;c:while(true){e=true;d:while(e===true){e=false;if(!v(b,a.g_vowel,97,305)){break d}break c}if(b._>=b.A){break b}b._++}c--;continue a}b._=g;break a}if(c>0){return false}b._=f;return true};a.prototype.P=function(){var f;var g;var h;var b;var a;var c;var d;var i;var j;var e;b=true;b:while(b===true){b=false;f=this._;a=true;a:while(a===true){a=false;g=this._;c:while(true){c=true;d:while(c===true){c=false;if(!s(this,2,'ad')){break d}break c}if(this._>=this.A){break a}this._++}i=this.I_strlen=2;if(!(i===this.A)){break a}this._=g;break b}j=this._=f;h=j;a:while(true){d=true;c:while(d===true){d=false;if(!s(this,5,'soyad')){break c}break a}if(this._>=this.A){return false}this._++}e=this.I_strlen=5;if(!(e===this.A)){return false}this._=h}return true};a.prototype.r_is_reserved_word=a.prototype.P;function x(a){var g;var h;var i;var c;var b;var d;var e;var j;var k;var f;c=true;b:while(c===true){c=false;g=a._;b=true;a:while(b===true){b=false;h=a._;c:while(true){d=true;d:while(d===true){d=false;if(!s(a,2,'ad')){break d}break c}if(a._>=a.A){break a}a._++}j=a.I_strlen=2;if(!(j===a.A)){break a}a._=h;break b}k=a._=g;i=k;a:while(true){e=true;c:while(e===true){e=false;if(!s(a,5,'soyad')){break c}break a}if(a._>=a.A){return false}a._++}f=a.I_strlen=5;if(!(f===a.A)){return false}a._=i}return true};a.prototype.x=function(){var d;var e;var a;var b;var c;var f;var g;var h;d=this._;a=true;a:while(a===true){a=false;if(!x(this)){break a}return false}f=this._=d;this.D=f;h=this._=g=this.A;e=g-h;b=true;a:while(b===true){b=false;if(!z(this)){break a}}this._=this.A-e;c=true;a:while(c===true){c=false;if(!w(this)){break a}}this._=this.D;return true};a.prototype.r_postlude=a.prototype.x;function O(a){var e;var f;var b;var c;var d;var g;var h;var i;e=a._;b=true;a:while(b===true){b=false;if(!x(a)){break a}return false}g=a._=e;a.D=g;i=a._=h=a.A;f=h-i;c=true;a:while(c===true){c=false;if(!z(a)){break a}}a._=a.A-f;d=true;a:while(d===true){d=false;if(!w(a)){break a}}a._=a.D;return true};a.prototype.H=function(){var c;var a;var b;var d;var e;if(!N(this)){return false}this.D=this._;e=this._=d=this.A;c=d-e;a=true;a:while(a===true){a=false;if(!J(this)){break a}}this._=this.A-c;if(!this.B_continue_stemming_noun_suffixes){return false}b=true;a:while(b===true){b=false;if(!L(this)){break a}}this._=this.D;return!O(this)?false:true};a.prototype.stem=a.prototype.H;a.prototype.L=function(b){return b instanceof a};a.prototype.equals=a.prototype.L;a.prototype.M=function(){var c;var a;var b;var d;c='TurkishStemmer';a=0;for(b=0;b<c.length;b++){d=c.charCodeAt(b);a=(a<<5)-a+d;a=a&a}return a|0};a.prototype.hashCode=a.prototype.M;a.serialVersionUID=1;j(a,'methodObject',function(){return new a});j(a,'a_0',function(){return[new d('m',-1,-1),new d('n',-1,-1),new d('miz',-1,-1),new d('niz',-1,-1),new d('muz',-1,-1),new d('nuz',-1,-1),new d('müz',-1,-1),new d('nüz',-1,-1),new d('mız',-1,-1),new d('nız',-1,-1)]});j(a,'a_1',function(){return[new d('leri',-1,-1),new d('ları',-1,-1)]});j(a,'a_2',function(){return[new d('ni',-1,-1),new d('nu',-1,-1),new d('nü',-1,-1),new d('nı',-1,-1)]});j(a,'a_3',function(){return[new d('in',-1,-1),new d('un',-1,-1),new d('ün',-1,-1),new d('ın',-1,-1)]});j(a,'a_4',function(){return[new d('a',-1,-1),new d('e',-1,-1)]});j(a,'a_5',function(){return[new d('na',-1,-1),new d('ne',-1,-1)]});j(a,'a_6',function(){return[new d('da',-1,-1),new d('ta',-1,-1),new d('de',-1,-1),new d('te',-1,-1)]});j(a,'a_7',function(){return[new d('nda',-1,-1),new d('nde',-1,-1)]});j(a,'a_8',function(){return[new d('dan',-1,-1),new d('tan',-1,-1),new d('den',-1,-1),new d('ten',-1,-1)]});j(a,'a_9',function(){return[new d('ndan',-1,-1),new d('nden',-1,-1)]});j(a,'a_10',function(){return[new d('la',-1,-1),new d('le',-1,-1)]});j(a,'a_11',function(){return[new d('ca',-1,-1),new d('ce',-1,-1)]});j(a,'a_12',function(){return[new d('im',-1,-1),new d('um',-1,-1),new d('üm',-1,-1),new d('ım',-1,-1)]});j(a,'a_13',function(){return[new d('sin',-1,-1),new d('sun',-1,-1),new d('sün',-1,-1),new d('sın',-1,-1)]});j(a,'a_14',function(){return[new d('iz',-1,-1),new d('uz',-1,-1),new d('üz',-1,-1),new d('ız',-1,-1)]});j(a,'a_15',function(){return[new d('siniz',-1,-1),new d('sunuz',-1,-1),new d('sünüz',-1,-1),new d('sınız',-1,-1)]});j(a,'a_16',function(){return[new d('lar',-1,-1),new d('ler',-1,-1)]});j(a,'a_17',function(){return[new d('niz',-1,-1),new d('nuz',-1,-1),new d('nüz',-1,-1),new d('nız',-1,-1)]});j(a,'a_18',function(){return[new d('dir',-1,-1),new d('tir',-1,-1),new d('dur',-1,-1),new d('tur',-1,-1),new d('dür',-1,-1),new d('tür',-1,-1),new d('dır',-1,-1),new d('tır',-1,-1)]});j(a,'a_19',function(){return[new d('casına',-1,-1),new d('cesine',-1,-1)]});j(a,'a_20',function(){return[new d('di',-1,-1),new d('ti',-1,-1),new d('dik',-1,-1),new d('tik',-1,-1),new d('duk',-1,-1),new d('tuk',-1,-1),new d('dük',-1,-1),new d('tük',-1,-1),new d('dık',-1,-1),new d('tık',-1,-1),new d('dim',-1,-1),new d('tim',-1,-1),new d('dum',-1,-1),new d('tum',-1,-1),new d('düm',-1,-1),new d('tüm',-1,-1),new d('dım',-1,-1),new d('tım',-1,-1),new d('din',-1,-1),new d('tin',-1,-1),new d('dun',-1,-1),new d('tun',-1,-1),new d('dün',-1,-1),new d('tün',-1,-1),new d('dın',-1,-1),new d('tın',-1,-1),new d('du',-1,-1),new d('tu',-1,-1),new d('dü',-1,-1),new d('tü',-1,-1),new d('dı',-1,-1),new d('tı',-1,-1)]});j(a,'a_21',function(){return[new d('sa',-1,-1),new d('se',-1,-1),new d('sak',-1,-1),new d('sek',-1,-1),new d('sam',-1,-1),new d('sem',-1,-1),new d('san',-1,-1),new d('sen',-1,-1)]});j(a,'a_22',function(){return[new d('miş',-1,-1),new d('muş',-1,-1),new d('müş',-1,-1),new d('mış',-1,-1)]});j(a,'a_23',function(){return[new d('b',-1,1),new d('c',-1,2),new d('d',-1,3),new d('ğ',-1,4)]});j(a,'g_vowel',function(){return[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,8,0,0,0,0,0,0,1]});j(a,'g_U',function(){return[1,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1]});j(a,'g_vowel1',function(){return[1,64,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]});j(a,'g_vowel2',function(){return[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130]});j(a,'g_vowel3',function(){return[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]});j(a,'g_vowel4',function(){return[17]});j(a,'g_vowel5',function(){return[65]});j(a,'g_vowel6',function(){return[65]});var y={'src/stemmer.jsx':{Stemmer:u},'src/turkish-stemmer.jsx':{TurkishStemmer:a}}}(JSX)) var Stemmer = JSX.require("src/turkish-stemmer.jsx").TurkishStemmer; diff --git a/sphinx/search/zh.py b/sphinx/search/zh.py index 48f169aea..6948a6ad4 100644 --- a/sphinx/search/zh.py +++ b/sphinx/search/zh.py @@ -4,7 +4,7 @@ Chinese search language: includes routine to split words. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py index f55158575..0a30ff82f 100644 --- a/sphinx/setup_command.py +++ b/sphinx/setup_command.py @@ -7,19 +7,19 @@ :author: Sebastian Wiesner :contact: basti.wiesner@gmx.net - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import sys from distutils.cmd import Command -from distutils.errors import DistutilsOptionError, DistutilsExecError +from distutils.errors import DistutilsExecError from io import StringIO from sphinx.application import Sphinx from sphinx.cmd.build import handle_exception -from sphinx.util.console import nocolor, color_terminal +from sphinx.util.console import color_terminal, nocolor from sphinx.util.docutils import docutils_namespace, patch_docutils from sphinx.util.osutil import abspath @@ -84,6 +84,7 @@ class BuildDoc(Command): ('link-index', 'i', 'Link index.html to the master doc'), ('copyright', None, 'The copyright string'), ('pdb', None, 'Start pdb on exception'), + ('verbosity', 'v', 'increase verbosity (can be repeated)'), ('nitpicky', 'n', 'nit-picky mode, warn about all missing references'), ('keep-going', None, 'With -W, keep going when getting warnings'), ] @@ -104,7 +105,8 @@ class BuildDoc(Command): self.config_dir = None # type: str self.link_index = False self.copyright = '' - self.verbosity = 0 + # Link verbosity to distutils' (which uses 1 by default). + self.verbosity = self.distribution.verbose - 1 # type: ignore self.traceback = False self.nitpicky = False self.keep_going = False @@ -119,20 +121,6 @@ class BuildDoc(Command): return root return os.curdir - # Overriding distutils' Command._ensure_stringlike which doesn't support - # unicode, causing finalize_options to fail if invoked again. Workaround - # for https://bugs.python.org/issue19570 - def _ensure_stringlike(self, option, what, default=None): - # type: (str, str, Any) -> Any - val = getattr(self, option) - if val is None: - setattr(self, option, default) - return default - elif not isinstance(val, str): - raise DistutilsOptionError("'%s' must be a %s (got `%s`)" - % (option, what, val)) - return val - def finalize_options(self): # type: () -> None self.ensure_string_list('builder') @@ -189,7 +177,7 @@ class BuildDoc(Command): builder, confoverrides, status_stream, freshenv=self.fresh_env, warningiserror=self.warning_is_error, - keep_going=self.keep_going) + verbosity=self.verbosity, keep_going=self.keep_going) app.build(force_all=self.all_files) if app.statuscode: raise DistutilsExecError( @@ -197,7 +185,7 @@ class BuildDoc(Command): except Exception as exc: handle_exception(app, self, exc, sys.stderr) if not self.pdb: - raise SystemExit(1) + raise SystemExit(1) from exc if not self.link_index: continue diff --git a/sphinx/templates/apidoc/package.rst_t b/sphinx/templates/apidoc/package.rst_t index 8630a87b7..b7380e8a0 100644 --- a/sphinx/templates/apidoc/package.rst_t +++ b/sphinx/templates/apidoc/package.rst_t @@ -35,7 +35,7 @@ Submodules ---------- {% if separatemodules %} {{ toctree(submodules) }} -{%- else %} +{% else %} {%- for submodule in submodules %} {% if show_headings %} {{- [submodule, "module"] | join(" ") | e | heading(2) }} @@ -43,7 +43,7 @@ Submodules {{ automodule(submodule, automodule_options) }} {% endfor %} {%- endif %} -{% endif %} +{%- endif %} {%- if not modulefirst and not is_namespace %} Module contents diff --git a/sphinx/templates/graphviz/graphviz.css b/sphinx/templates/graphviz/graphviz.css index 8ab69e014..b340734c7 100644 --- a/sphinx/templates/graphviz/graphviz.css +++ b/sphinx/templates/graphviz/graphviz.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- graphviz extension. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/templates/quickstart/Makefile_t b/sphinx/templates/quickstart/Makefile_t index 7b656dff0..af9c56304 100644 --- a/sphinx/templates/quickstart/Makefile_t +++ b/sphinx/templates/quickstart/Makefile_t @@ -49,7 +49,7 @@ help: .PHONY: clean clean: - rm -rf $(BUILDDIR)/* + rm -rf $(BUILDDIR) .PHONY: latexpdf latexpdf: diff --git a/sphinx/testing/__init__.py b/sphinx/testing/__init__.py index dd9f32462..67263eff9 100644 --- a/sphinx/testing/__init__.py +++ b/sphinx/testing/__init__.py @@ -9,6 +9,6 @@ pytest_plugins = 'sphinx.testing.fixtures' - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/testing/comparer.py b/sphinx/testing/comparer.py index ddd818394..642cc8444 100644 --- a/sphinx/testing/comparer.py +++ b/sphinx/testing/comparer.py @@ -4,7 +4,7 @@ Sphinx test comparer for pytest - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import difflib diff --git a/sphinx/testing/fixtures.py b/sphinx/testing/fixtures.py index eec3b4208..1cf66283f 100644 --- a/sphinx/testing/fixtures.py +++ b/sphinx/testing/fixtures.py @@ -4,7 +4,7 @@ Sphinx test fixtures for pytest - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -21,6 +21,20 @@ import pytest from sphinx.testing import util from sphinx.testing.util import SphinxTestApp, SphinxTestAppWrapperForSkipBuilding +DEFAULT_ENABLED_MARKERS = [ + ( + 'sphinx(builder, testroot=None, freshenv=False, confoverrides=None, tags=None,' + ' docutilsconf=None, parallel=0): arguments to initialize the sphinx test application.' + ), + 'test_params(shared_result=...): test parameters.', +] + + +def pytest_configure(config): + # register custom markers + for marker in DEFAULT_ENABLED_MARKERS: + config.addinivalue_line('markers', marker) + @pytest.fixture(scope='session') def rootdir() -> str: @@ -79,7 +93,7 @@ def app_params(request: Any, test_params: Dict, shared_result: SharedResult, if test_params['shared_result']: if 'srcdir' in kwargs: - raise pytest.Exception('You can not spcify shared_result and ' + raise pytest.Exception('You can not specify shared_result and ' 'srcdir in same time.') kwargs['srcdir'] = test_params['shared_result'] restore = shared_result.restore(test_params['shared_result']) @@ -236,3 +250,15 @@ def tempdir(tmpdir: str) -> "util.path": this fixture is for compat with old test implementation. """ return util.path(tmpdir) + + +@pytest.fixture +def rollback_sysmodules(): + """Rollback sys.modules to before testing to unload modules during tests.""" + try: + sysmodules = list(sys.modules) + yield + finally: + for modname in list(sys.modules): + if modname not in sysmodules: + sys.modules.pop(modname) diff --git a/sphinx/testing/path.py b/sphinx/testing/path.py index 4c3702e3d..efc5e8f63 100644 --- a/sphinx/testing/path.py +++ b/sphinx/testing/path.py @@ -2,7 +2,7 @@ sphinx.testing.path ~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -11,11 +11,10 @@ import os import shutil import sys import warnings -from typing import Any, Callable, IO, List +from typing import IO, Any, Callable, List from sphinx.deprecation import RemovedInSphinx50Warning - FILESYSTEMENCODING = sys.getfilesystemencoding() or sys.getdefaultencoding() diff --git a/sphinx/testing/restructuredtext.py b/sphinx/testing/restructuredtext.py index b25d7f98a..bb095b410 100644 --- a/sphinx/testing/restructuredtext.py +++ b/sphinx/testing/restructuredtext.py @@ -2,7 +2,7 @@ sphinx.testing.restructuredtext ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py index 450241f55..7d0cde143 100644 --- a/sphinx/testing/util.py +++ b/sphinx/testing/util.py @@ -4,15 +4,16 @@ Sphinx test suite utilities - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import functools import os import re import sys import warnings from io import StringIO -from typing import Any, Dict, Generator, IO, List, Pattern +from typing import IO, Any, Dict, Generator, List, Pattern from xml.etree import ElementTree from docutils import nodes @@ -20,13 +21,11 @@ from docutils.nodes import Node from docutils.parsers.rst import directives, roles from sphinx import application, locale -from sphinx.builders.latex import LaTeXBuilder from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.pycode import ModuleAnalyzer from sphinx.testing.path import path from sphinx.util.osutil import relpath - __all__ = [ 'Struct', 'SphinxTestApp', 'SphinxTestAppWrapperForSkipBuilding', @@ -108,7 +107,7 @@ class SphinxTestApp(application.Sphinx): def __init__(self, buildername: str = 'html', srcdir: path = None, freshenv: bool = False, confoverrides: Dict = None, status: IO = None, warning: IO = None, - tags: List[str] = None, docutilsconf: str = None) -> None: + tags: List[str] = None, docutilsconf: str = None, parallel: int = 0) -> None: if docutilsconf is not None: (srcdir / 'docutils.conf').write_text(docutilsconf) @@ -133,14 +132,13 @@ class SphinxTestApp(application.Sphinx): try: super().__init__(srcdir, confdir, outdir, doctreedir, buildername, confoverrides, status, warning, - freshenv, warningiserror, tags) + freshenv, warningiserror, tags, parallel=parallel) except Exception: self.cleanup() raise def cleanup(self, doctrees: bool = False) -> None: ModuleAnalyzer.cache.clear() - LaTeXBuilder.usepackages = [] locale.translators.clear() sys.path[:] = self._saved_path sys.modules.pop('autodoc_fodder', None) @@ -195,3 +193,13 @@ def find_files(root: str, suffix: bool = None) -> Generator[str, None, None]: def strip_escseq(text: str) -> str: return re.sub('\x1b.*?m', '', text) + + +def simple_decorator(f): + """ + A simple decorator that does nothing, for tests to use. + """ + @functools.wraps(f) + def wrapper(*args, **kwargs): + return f(*args, **kwargs) + return wrapper diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 63676d46d..343924753 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -6,7 +6,7 @@ % \NeedsTeXFormat{LaTeX2e}[1995/12/01] -\ProvidesPackage{sphinx}[2019/09/02 v2.3.0 LaTeX package (Sphinx markup)] +\ProvidesPackage{sphinx}[2021/01/23 v3.5.0 LaTeX package (Sphinx markup)] % provides \ltx@ifundefined % (many packages load ltxcmds: graphicx does for pdftex and lualatex but @@ -588,12 +588,14 @@ {% classes with \chapter command \fancypagestyle{normal}{ \fancyhf{} - % FIXME: this presupposes "twoside". - % If "oneside" class option, there are warnings in LaTeX log. - \fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}} + \fancyfoot[RO]{{\py@HeaderFamily\thepage}} \fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}} - \fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}} - \fancyhead[LE,RO]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}} + \fancyhead[RO]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}} + \if@twoside + \fancyfoot[LE]{{\py@HeaderFamily\thepage}} + \fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}} + \fancyhead[LE]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}} + \fi \renewcommand{\headrulewidth}{0.4pt} \renewcommand{\footrulewidth}{0.4pt} % define chaptermark with \@chappos when \@chappos is available for Japanese @@ -605,7 +607,8 @@ % page of a chapter `clean.' \fancypagestyle{plain}{ \fancyhf{} - \fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}} + \fancyfoot[RO]{{\py@HeaderFamily\thepage}} + \if@twoside\fancyfoot[LE]{{\py@HeaderFamily\thepage}}\fi \renewcommand{\headrulewidth}{0pt} \renewcommand{\footrulewidth}{0.4pt} } @@ -841,6 +844,12 @@ %% NUMBERING OF FIGURES, TABLES, AND LITERAL BLOCKS + +% Everything is delayed to \begin{document} to allow hyperref patches into +% \newcounter to solve duplicate label problems for internal hyperlinks to +% code listings (literalblock counter). User or extension re-definitions of +% \theliteralblock, et al., thus have also to be delayed. (changed at 3.5.0) +\AtBeginDocument{% \ltx@ifundefined{c@chapter} {\newcounter{literalblock}}% {\newcounter{literalblock}[chapter]% @@ -886,7 +895,7 @@ \@addtoreset{literalblock}{section}% \ifspx@opt@mathnumfig \@addtoreset{equation}{section}% - \fi + \fi% \g@addto@macro\spx@preAthefigure{\ifnum\c@section>\z@\arabic{section}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -896,7 +905,7 @@ \@addtoreset{literalblock}{subsection}% \ifspx@opt@mathnumfig \@addtoreset{equation}{subsection}% - \fi + \fi% \g@addto@macro\spx@preAthefigure{\ifnum\c@subsection>\z@\arabic{subsection}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -906,7 +915,7 @@ \@addtoreset{literalblock}{subsubsection}% \ifspx@opt@mathnumfig \@addtoreset{equation}{subsubsection}% - \fi + \fi% \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubsection>\z@\arabic{subsubsection}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -916,7 +925,7 @@ \@addtoreset{literalblock}{paragraph}% \ifspx@opt@mathnumfig \@addtoreset{equation}{paragraph}% - \fi + \fi% \g@addto@macro\spx@preAthefigure{\ifnum\c@subparagraph>\z@\arabic{subparagraph}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -926,7 +935,7 @@ \@addtoreset{literalblock}{subparagraph}% \ifspx@opt@mathnumfig \@addtoreset{equation}{subparagraph}% - \fi + \fi% \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubparagraph>\z@\arabic{subsubparagraph}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -943,7 +952,7 @@ \g@addto@macro\theequation{\arabic{equation}}% \fi \fi - +}% end of big \AtBeginDocument %% LITERAL BLOCKS % @@ -953,9 +962,9 @@ % - with possibly of a top caption, non-separable by pagebreak. % - and usable inside tables or footnotes ("footnotehyper-sphinx"). -% For extensions which use \OriginalVerbatim and compatibility with Sphinx < -% 1.5, we define and use these when (unmodified) Verbatim will be needed. But -% Sphinx >= 1.5 does not modify the \Verbatim macro anymore. +% Prior to Sphinx 1.5, \Verbatim and \endVerbatim were modified by Sphinx. +% The aliases defined here are used in sphinxVerbatim environment and can +% serve as hook-points with no need to modify \Verbatim itself. \let\OriginalVerbatim \Verbatim \let\endOriginalVerbatim\endVerbatim @@ -1813,7 +1822,7 @@ % fix a space-gobbling issue due to LaTeX's original \do@noligs % TODO: using \@noligs as patched by upquote.sty is now unneeded because % either ` and ' are escaped (non-unicode engines) or they don't build -% ligatures (unicode engines). Thus remove this and unify handling of `, <, >, +% ligatures (unicode engines). Thus remove this and unify handling of `, <, >, % ' and - with the characters . , ; ? ! / as handled via % \sphinxbreaksviaactive. % Hence \sphinx@do@noligs will be removed, or rather replaced with code @@ -1895,7 +1904,7 @@ % Special characters % % This definition prevents en-dash and em-dash TeX ligatures. -% +% % It inserts a potential breakpoint after the hyphen. This is to keep in sync % with behavior in code-blocks, parsed and inline literals. For a breakpoint % before the hyphen use \leavevmode\kern\z@- (within \makeatletter/\makeatother) diff --git a/sphinx/texinputs/sphinxcyrillic.sty b/sphinx/texinputs/sphinxcyrillic.sty index 482b4e3f7..6747b5ec6 100644 --- a/sphinx/texinputs/sphinxcyrillic.sty +++ b/sphinx/texinputs/sphinxcyrillic.sty @@ -15,7 +15,7 @@ % https://tex.stackexchange.com/a/460325/ % 159 Cyrillic glyphs as available in X2 TeX 8bit font encoding % This assumes inputenc loaded with utf8 option, or LaTeX release -% as recent as 2018/04/01 which does it automatically. +% as recent as 2018/04/01 which does it automatically. \@tfor\next:=% {Ё}{Ђ}{Є}{Ѕ}{І}{Ј}{Љ}{Њ}{Ћ}{Ў}{Џ}{А}{Б}{В}{Г}{Д}{Е}{Ж}{З}{И}{Й}% {К}{Л}{М}{Н}{О}{П}{Р}{С}{Т}{У}{Ф}{Х}{Ц}{Ч}{Ш}{Щ}{Ъ}{Ы}{Ь}{Э}{Ю}% diff --git a/sphinx/texinputs/sphinxhowto.cls b/sphinx/texinputs/sphinxhowto.cls index 57d73cebf..0848a79fd 100644 --- a/sphinx/texinputs/sphinxhowto.cls +++ b/sphinx/texinputs/sphinxhowto.cls @@ -76,7 +76,7 @@ \endgroup \noindent\rule{\textwidth}{1pt}\par \vspace{12pt}% -} +} \newcommand\sphinxtableofcontentshook{} \pagenumbering{arabic} diff --git a/sphinx/themes/agogo/layout.html b/sphinx/themes/agogo/layout.html index 26c37b10e..1d9df693b 100644 --- a/sphinx/themes/agogo/layout.html +++ b/sphinx/themes/agogo/layout.html @@ -5,7 +5,7 @@ Sphinx layout template for the agogo theme, originally written by Andi Albrecht. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/agogo/static/agogo.css_t b/sphinx/themes/agogo/static/agogo.css_t index d74604ac1..489ec17ea 100644 --- a/sphinx/themes/agogo/static/agogo.css_t +++ b/sphinx/themes/agogo/static/agogo.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- agogo theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -207,7 +207,6 @@ div.document .section:first-child { div.document div.highlight { padding: 3px; - background-color: #eeeeec; border-top: 2px solid #dddddd; border-bottom: 2px solid #dddddd; margin-top: .8em; diff --git a/sphinx/themes/basic/defindex.html b/sphinx/themes/basic/defindex.html index 2f8477c31..8ca5748ac 100644 --- a/sphinx/themes/basic/defindex.html +++ b/sphinx/themes/basic/defindex.html @@ -4,7 +4,7 @@ Default template for the "index" page. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #}{{ warn('Now base template defindex.html is deprecated.') }} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/domainindex.html b/sphinx/themes/basic/domainindex.html index f4f742338..1ccab0286 100644 --- a/sphinx/themes/basic/domainindex.html +++ b/sphinx/themes/basic/domainindex.html @@ -4,7 +4,7 @@ Template for domain indices (module index, ...). - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/genindex-single.html b/sphinx/themes/basic/genindex-single.html index b327eb620..1182fdada 100644 --- a/sphinx/themes/basic/genindex-single.html +++ b/sphinx/themes/basic/genindex-single.html @@ -4,7 +4,7 @@ Template for a "single" page of a split index. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {% macro indexentries(firstname, links) %} diff --git a/sphinx/themes/basic/genindex-split.html b/sphinx/themes/basic/genindex-split.html index e9db8574d..8b79dc8dc 100644 --- a/sphinx/themes/basic/genindex-split.html +++ b/sphinx/themes/basic/genindex-split.html @@ -4,7 +4,7 @@ Template for a "split" index overview page. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/genindex.html b/sphinx/themes/basic/genindex.html index fb769737f..7f16c3544 100644 --- a/sphinx/themes/basic/genindex.html +++ b/sphinx/themes/basic/genindex.html @@ -4,7 +4,7 @@ Template for an "all-in-one" index. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/globaltoc.html b/sphinx/themes/basic/globaltoc.html index 2f16655cf..a47c32cc0 100644 --- a/sphinx/themes/basic/globaltoc.html +++ b/sphinx/themes/basic/globaltoc.html @@ -4,8 +4,8 @@ Sphinx sidebar template: global table of contents. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} <h3><a href="{{ pathto(master_doc)|e }}">{{ _('Table of Contents') }}</a></h3> -{{ toctree(includehidden=theme_globaltoc_includehidden, collapse=theme_globaltoc_collapse) }} +{{ toctree(includehidden=theme_globaltoc_includehidden, collapse=theme_globaltoc_collapse, maxdepth=theme_globaltoc_maxdepth) }} diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index 50feffd71..bd56681c0 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -4,7 +4,7 @@ Master layout template for Sphinx themes. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- block doctype -%}{%- if html5_doctype %} @@ -18,7 +18,7 @@ {%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and (sidebars != []) %} {%- set url_root = pathto('', 1) %} -{# XXX necessary? #} +{# URL root should never be #, then all links are fragments #} {%- if url_root == '#' %}{% set url_root = '' %}{% endif %} {%- if not embedded and docstitle %} {%- set titlesuffix = " — "|safe + docstitle|e %} @@ -88,15 +88,15 @@ {%- endmacro %} {%- macro script() %} - <script id="documentation_options" data-url_root="{{ pathto('', 1) }}" src="{{ pathto('_static/documentation_options.js', 1) }}"></script> + <script id="documentation_options" data-url_root="{{ url_root }}" src="{{ pathto('_static/documentation_options.js', 1) }}"></script> {%- for js in script_files %} {{ js_tag(js) }} {%- endfor %} {%- endmacro %} {%- macro css() %} - <link rel="stylesheet" href="{{ pathto('_static/' + style, 1)|e }}" type="text/css" /> <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" /> + <link rel="stylesheet" href="{{ pathto('_static/' + style, 1)|e }}" type="text/css" /> {%- for css in css_files %} {%- if css|attr("filename") %} {{ css_tag(css) }} @@ -120,7 +120,7 @@ {%- else %} <meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" /> {%- endif %} - <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> {{- metatags }} {%- block htmltitle %} <title>{{ title|striptags|e }}{{ titlesuffix }}</title> diff --git a/sphinx/themes/basic/localtoc.html b/sphinx/themes/basic/localtoc.html index 0e1c5511b..c15ad2708 100644 --- a/sphinx/themes/basic/localtoc.html +++ b/sphinx/themes/basic/localtoc.html @@ -4,7 +4,7 @@ Sphinx sidebar template: local table of contents. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- if display_toc %} diff --git a/sphinx/themes/basic/page.html b/sphinx/themes/basic/page.html index c9c351167..5878bdeeb 100644 --- a/sphinx/themes/basic/page.html +++ b/sphinx/themes/basic/page.html @@ -4,7 +4,7 @@ Master template for simple pages. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/relations.html b/sphinx/themes/basic/relations.html index 5a2113cf0..c4391fe4d 100644 --- a/sphinx/themes/basic/relations.html +++ b/sphinx/themes/basic/relations.html @@ -4,7 +4,7 @@ Sphinx sidebar template: relation links. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- if prev %} diff --git a/sphinx/themes/basic/search.html b/sphinx/themes/basic/search.html index 2673369f2..453a35fb9 100644 --- a/sphinx/themes/basic/search.html +++ b/sphinx/themes/basic/search.html @@ -4,7 +4,7 @@ Template for the search page. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} @@ -12,6 +12,7 @@ {%- block scripts %} {{ super() }} <script src="{{ pathto('_static/searchtools.js', 1) }}"></script> + <script src="{{ pathto('_static/language_data.js', 1) }}"></script> {%- endblock %} {% block extrahead %} <script src="{{ pathto('searchindex.js', 1) }}" defer></script> diff --git a/sphinx/themes/basic/searchbox.html b/sphinx/themes/basic/searchbox.html index 6ce202786..68f933f66 100644 --- a/sphinx/themes/basic/searchbox.html +++ b/sphinx/themes/basic/searchbox.html @@ -4,7 +4,7 @@ Sphinx sidebar template: quick search box. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- if pagename != "search" and builder != "singlehtml" %} diff --git a/sphinx/themes/basic/sourcelink.html b/sphinx/themes/basic/sourcelink.html index 2ff5d1b66..512611230 100644 --- a/sphinx/themes/basic/sourcelink.html +++ b/sphinx/themes/basic/sourcelink.html @@ -4,7 +4,7 @@ Sphinx sidebar template: "show source" link. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- if show_source and has_source and sourcename %} diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index 45908ece1..3bb3ea705 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- basic theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -15,6 +15,12 @@ div.clearer { clear: both; } +div.section::after { + display: block; + content: ''; + clear: left; +} + /* -- relbar ---------------------------------------------------------------- */ div.related { @@ -316,7 +322,7 @@ img.align-default, .figure.align-default { div.sidebar { margin: 0 0 0.5em 1em; border: 1px solid #ddb; - padding: 7px 7px 0 7px; + padding: 7px; background-color: #ffe; width: 40%; float: right; @@ -328,17 +334,16 @@ p.sidebar-title { font-weight: bold; } -div.admonition, div.topic, pre, div[class|="highlight"] { - clear: both; +div.admonition, div.topic, blockquote { + clear: left; } /* -- topics ---------------------------------------------------------------- */ div.topic { border: 1px solid #ccc; - padding: 7px 7px 0 7px; + padding: 7px; margin: 10px 0 10px 0; - overflow-x: auto; } p.topic-title { @@ -353,17 +358,12 @@ div.admonition { margin-top: 10px; margin-bottom: 10px; padding: 7px; - overflow-x: auto; } div.admonition dt { font-weight: bold; } -div.admonition dl { - margin-bottom: 0; -} - p.admonition-title { margin: 0px 10px 5px 0px; font-weight: bold; @@ -374,6 +374,23 @@ div.body p.centered { margin-top: 25px; } +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + /* -- tables ---------------------------------------------------------------- */ table.docutils { @@ -426,13 +443,13 @@ table.citation td { border-bottom: none; } -th > p:first-child, -td > p:first-child { +th > :first-child, +td > :first-child { margin-top: 0px; } -th > p:last-child, -td > p:last-child { +th > :last-child, +td > :last-child { margin-bottom: 0px; } @@ -478,6 +495,10 @@ table.field-list td, table.field-list th { /* -- hlist styles ---------------------------------------------------------- */ +table.hlist { + margin: 1em 0; +} + table.hlist td { vertical-align: top; } @@ -505,14 +526,33 @@ ol.upperroman { list-style: upper-roman; } -li > p:first-child { +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { margin-top: 0px; } -li > p:last-child { +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { margin-bottom: 0px; } +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + dl.footnote > dt, dl.citation > dt { float: left; @@ -557,7 +597,7 @@ dl { margin-bottom: 15px; } -dd > p:first-child { +dd > :first-child { margin-top: 0px; } @@ -571,6 +611,11 @@ dd { margin-left: 30px; } +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + dt:target, span.highlighted { background-color: #fbe54e; } @@ -648,6 +693,10 @@ pre { overflow-y: hidden; /* fixes display issues on Chrome browsers */ } +pre, div[class*="highlight-"] { + clear: both; +} + span.pre { -moz-hyphens: none; -ms-hyphens: none; @@ -655,6 +704,10 @@ span.pre { hyphens: none; } +div[class*="highlight-"] { + margin: 1em 0; +} + td.linenos pre { border: 0; background-color: transparent; @@ -663,7 +716,6 @@ td.linenos pre { table.highlighttable { display: block; - margin: 1em 0; } table.highlighttable tbody { @@ -680,7 +732,7 @@ table.highlighttable td { } table.highlighttable td.linenos { - padding: 0 0.5em; + padding-right: 0.5em; } table.highlighttable td.code { @@ -692,11 +744,12 @@ table.highlighttable td.code { display: block; } +div.highlight pre, table.highlighttable pre { margin: 0; } -div.code-block-caption + div > table.highlighttable { +div.code-block-caption + div { margin-top: 0; } @@ -710,11 +763,8 @@ div.code-block-caption code { background-color: transparent; } -div.code-block-caption + div > div.highlight > pre { - margin-top: 0; -} - table.highlighttable td.linenos, +span.linenos, div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ user-select: none; } diff --git a/sphinx/themes/basic/static/doctools.js b/sphinx/themes/basic/static/doctools.js index daccd209d..144884ea6 100644 --- a/sphinx/themes/basic/static/doctools.js +++ b/sphinx/themes/basic/static/doctools.js @@ -4,7 +4,7 @@ * * Sphinx JavaScript utilities for all documentation. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -285,9 +285,10 @@ var Documentation = { initOnKeyListeners: function() { $(document).keydown(function(event) { var activeElementType = document.activeElement.tagName; - // don't navigate when in search box or textarea + // don't navigate when in search box, textarea, dropdown or button if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' - && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey) { + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { switch (event.keyCode) { case 37: // left var prevHref = $('link[rel="prev"]').prop('href'); diff --git a/sphinx/themes/basic/static/language_data.js_t b/sphinx/themes/basic/static/language_data.js_t index 531813877..1425b022a 100644 --- a/sphinx/themes/basic/static/language_data.js_t +++ b/sphinx/themes/basic/static/language_data.js_t @@ -5,7 +5,7 @@ * This script contains the language-specific data used by searchtools.js, * namely the list of stopwords, stemmer, scorer and splitter. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js index ab5649965..6fc9e7f33 100644 --- a/sphinx/themes/basic/static/searchtools.js +++ b/sphinx/themes/basic/static/searchtools.js @@ -4,7 +4,7 @@ * * Sphinx JavaScript utilities for the full-text search. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -59,10 +59,10 @@ var Search = { _pulse_status : -1, htmlToText : function(htmlString) { - var htmlElement = document.createElement('span'); - htmlElement.innerHTML = htmlString; - $(htmlElement).find('.headerlink').remove(); - docContent = $(htmlElement).find('[role=main]')[0]; + var virtualDocument = document.implementation.createHTMLDocument('virtual'); + var htmlElement = $(htmlString, virtualDocument); + htmlElement.find('.headerlink').remove(); + docContent = htmlElement.find('[role=main]')[0]; if(docContent === undefined) { console.warn("Content block not found. Sphinx search tries to obtain it " + "via '[role=main]'. Could you check your theme or template."); @@ -166,8 +166,7 @@ var Search = { objectterms.push(tmp[i].toLowerCase()); } - if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) || - tmp[i] === "") { + if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i] === "") { // skip this "word" continue; } diff --git a/sphinx/themes/basic/static/underscore-1.12.0.js b/sphinx/themes/basic/static/underscore-1.12.0.js new file mode 100644 index 000000000..3af6352e6 --- /dev/null +++ b/sphinx/themes/basic/static/underscore-1.12.0.js @@ -0,0 +1,2027 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define('underscore', factory) : + (global = global || self, (function () { + var current = global._; + var exports = global._ = factory(); + exports.noConflict = function () { global._ = current; return exports; }; + }())); +}(this, (function () { + // Underscore.js 1.12.0 + // https://underscorejs.org + // (c) 2009-2020 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + // Underscore may be freely distributed under the MIT license. + + // Current version. + var VERSION = '1.12.0'; + + // Establish the root object, `window` (`self`) in the browser, `global` + // on the server, or `this` in some virtual machines. We use `self` + // instead of `window` for `WebWorker` support. + var root = typeof self == 'object' && self.self === self && self || + typeof global == 'object' && global.global === global && global || + Function('return this')() || + {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype; + var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null; + + // Create quick reference variables for speed access to core prototypes. + var push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // Modern feature detection. + var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', + supportsDataView = typeof DataView !== 'undefined'; + + // All **ECMAScript 5+** native function implementations that we hope to use + // are declared here. + var nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeCreate = Object.create, + nativeIsView = supportsArrayBuffer && ArrayBuffer.isView; + + // Create references to these builtin functions because we override them. + var _isNaN = isNaN, + _isFinite = isFinite; + + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + + // The largest integer that can be represented exactly. + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + + // Some functions take a variable number of arguments, or a few expected + // arguments at the beginning and then a variable number of values to operate + // on. This helper accumulates all remaining arguments past the function’s + // argument length (or an explicit `startIndex`), into an array that becomes + // the last argument. Similar to ES6’s "rest parameter". + function restArguments(func, startIndex) { + startIndex = startIndex == null ? func.length - 1 : +startIndex; + return function() { + var length = Math.max(arguments.length - startIndex, 0), + rest = Array(length), + index = 0; + for (; index < length; index++) { + rest[index] = arguments[index + startIndex]; + } + switch (startIndex) { + case 0: return func.call(this, rest); + case 1: return func.call(this, arguments[0], rest); + case 2: return func.call(this, arguments[0], arguments[1], rest); + } + var args = Array(startIndex + 1); + for (index = 0; index < startIndex; index++) { + args[index] = arguments[index]; + } + args[startIndex] = rest; + return func.apply(this, args); + }; + } + + // Is a given variable an object? + function isObject(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + } + + // Is a given value equal to null? + function isNull(obj) { + return obj === null; + } + + // Is a given variable undefined? + function isUndefined(obj) { + return obj === void 0; + } + + // Is a given value a boolean? + function isBoolean(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + } + + // Is a given value a DOM element? + function isElement(obj) { + return !!(obj && obj.nodeType === 1); + } + + // Internal function for creating a `toString`-based type tester. + function tagTester(name) { + var tag = '[object ' + name + ']'; + return function(obj) { + return toString.call(obj) === tag; + }; + } + + var isString = tagTester('String'); + + var isNumber = tagTester('Number'); + + var isDate = tagTester('Date'); + + var isRegExp = tagTester('RegExp'); + + var isError = tagTester('Error'); + + var isSymbol = tagTester('Symbol'); + + var isArrayBuffer = tagTester('ArrayBuffer'); + + var isFunction = tagTester('Function'); + + // Optimize `isFunction` if appropriate. Work around some `typeof` bugs in old + // v8, IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236). + var nodelist = root.document && root.document.childNodes; + if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') { + isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } + + var isFunction$1 = isFunction; + + var hasObjectTag = tagTester('Object'); + + // In IE 10 - Edge 13, `DataView` has string tag `'[object Object]'`. + // In IE 11, the most common among them, this problem also applies to + // `Map`, `WeakMap` and `Set`. + var hasStringTagBug = ( + supportsDataView && hasObjectTag(new DataView(new ArrayBuffer(8))) + ), + isIE11 = (typeof Map !== 'undefined' && hasObjectTag(new Map)); + + var isDataView = tagTester('DataView'); + + // In IE 10 - Edge 13, we need a different heuristic + // to determine whether an object is a `DataView`. + function ie10IsDataView(obj) { + return obj != null && isFunction$1(obj.getInt8) && isArrayBuffer(obj.buffer); + } + + var isDataView$1 = (hasStringTagBug ? ie10IsDataView : isDataView); + + // Is a given value an array? + // Delegates to ECMA5's native `Array.isArray`. + var isArray = nativeIsArray || tagTester('Array'); + + // Internal function to check whether `key` is an own property name of `obj`. + function has(obj, key) { + return obj != null && hasOwnProperty.call(obj, key); + } + + var isArguments = tagTester('Arguments'); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + (function() { + if (!isArguments(arguments)) { + isArguments = function(obj) { + return has(obj, 'callee'); + }; + } + }()); + + var isArguments$1 = isArguments; + + // Is a given object a finite number? + function isFinite$1(obj) { + return !isSymbol(obj) && _isFinite(obj) && !isNaN(parseFloat(obj)); + } + + // Is the given value `NaN`? + function isNaN$1(obj) { + return isNumber(obj) && _isNaN(obj); + } + + // Predicate-generating function. Often useful outside of Underscore. + function constant(value) { + return function() { + return value; + }; + } + + // Common internal logic for `isArrayLike` and `isBufferLike`. + function createSizePropertyCheck(getSizeProperty) { + return function(collection) { + var sizeProperty = getSizeProperty(collection); + return typeof sizeProperty == 'number' && sizeProperty >= 0 && sizeProperty <= MAX_ARRAY_INDEX; + } + } + + // Internal helper to generate a function to obtain property `key` from `obj`. + function shallowProperty(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; + } + + // Internal helper to obtain the `byteLength` property of an object. + var getByteLength = shallowProperty('byteLength'); + + // Internal helper to determine whether we should spend extensive checks against + // `ArrayBuffer` et al. + var isBufferLike = createSizePropertyCheck(getByteLength); + + // Is a given value a typed array? + var typedArrayPattern = /\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/; + function isTypedArray(obj) { + // `ArrayBuffer.isView` is the most future-proof, so use it when available. + // Otherwise, fall back on the above regular expression. + return nativeIsView ? (nativeIsView(obj) && !isDataView$1(obj)) : + isBufferLike(obj) && typedArrayPattern.test(toString.call(obj)); + } + + var isTypedArray$1 = supportsArrayBuffer ? isTypedArray : constant(false); + + // Internal helper to obtain the `length` property of an object. + var getLength = shallowProperty('length'); + + // Internal helper to create a simple lookup structure. + // `collectNonEnumProps` used to depend on `_.contains`, but this led to + // circular imports. `emulatedSet` is a one-off solution that only works for + // arrays of strings. + function emulatedSet(keys) { + var hash = {}; + for (var l = keys.length, i = 0; i < l; ++i) hash[keys[i]] = true; + return { + contains: function(key) { return hash[key]; }, + push: function(key) { + hash[key] = true; + return keys.push(key); + } + }; + } + + // Internal helper. Checks `keys` for the presence of keys in IE < 9 that won't + // be iterated by `for key in ...` and thus missed. Extends `keys` in place if + // needed. + function collectNonEnumProps(obj, keys) { + keys = emulatedSet(keys); + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = isFunction$1(constructor) && constructor.prototype || ObjProto; + + // Constructor is a special case. + var prop = 'constructor'; + if (has(obj, prop) && !keys.contains(prop)) keys.push(prop); + + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !keys.contains(prop)) { + keys.push(prop); + } + } + } + + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys`. + function keys(obj) { + if (!isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (has(obj, key)) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + } + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + function isEmpty(obj) { + if (obj == null) return true; + // Skip the more expensive `toString`-based type checks if `obj` has no + // `.length`. + var length = getLength(obj); + if (typeof length == 'number' && ( + isArray(obj) || isString(obj) || isArguments$1(obj) + )) return length === 0; + return getLength(keys(obj)) === 0; + } + + // Returns whether an object has a given set of `key:value` pairs. + function isMatch(object, attrs) { + var _keys = keys(attrs), length = _keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = _keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; + } + + // If Underscore is called as a function, it returns a wrapped object that can + // be used OO-style. This wrapper holds altered versions of all functions added + // through `_.mixin`. Wrapped objects may be chained. + function _(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + } + + _.VERSION = VERSION; + + // Extracts the result from a wrapped and chained object. + _.prototype.value = function() { + return this._wrapped; + }; + + // Provide unwrapping proxies for some methods used in engine operations + // such as arithmetic and JSON stringification. + _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; + + _.prototype.toString = function() { + return String(this._wrapped); + }; + + // Internal function to wrap or shallow-copy an ArrayBuffer, + // typed array or DataView to a new view, reusing the buffer. + function toBufferView(bufferSource) { + return new Uint8Array( + bufferSource.buffer || bufferSource, + bufferSource.byteOffset || 0, + getByteLength(bufferSource) + ); + } + + // We use this string twice, so give it a name for minification. + var tagDataView = '[object DataView]'; + + // Internal recursive comparison function for `_.isEqual`. + function eq(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // `null` or `undefined` only equal to itself (strict comparison). + if (a == null || b == null) return false; + // `NaN`s are equivalent, but non-reflexive. + if (a !== a) return b !== b; + // Exhaust primitive checks + var type = typeof a; + if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; + return deepEq(a, b, aStack, bStack); + } + + // Internal recursive comparison function for `_.isEqual`. + function deepEq(a, b, aStack, bStack) { + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + // Work around a bug in IE 10 - Edge 13. + if (hasStringTagBug && className == '[object Object]' && isDataView$1(a)) { + if (!isDataView$1(b)) return false; + className = tagDataView; + } + switch (className) { + // These types are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN. + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + case '[object Symbol]': + return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); + case '[object ArrayBuffer]': + case tagDataView: + // Coerce to typed array so we can fall through. + return deepEq(toBufferView(a), toBufferView(b), aStack, bStack); + } + + var areArrays = className === '[object Array]'; + if (!areArrays && isTypedArray$1(a)) { + var byteLength = getByteLength(a); + if (byteLength !== getByteLength(b)) return false; + if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) return true; + areArrays = true; + } + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(isFunction$1(aCtor) && aCtor instanceof aCtor && + isFunction$1(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var _keys = keys(a), key; + length = _keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = _keys[length]; + if (!(has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + } + + // Perform a deep comparison to check if two objects are equal. + function isEqual(a, b) { + return eq(a, b); + } + + // Retrieve all the enumerable property names of an object. + function allKeys(obj) { + if (!isObject(obj)) return []; + var keys = []; + for (var key in obj) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + } + + // Since the regular `Object.prototype.toString` type tests don't work for + // some types in IE 11, we use a fingerprinting heuristic instead, based + // on the methods. It's not great, but it's the best we got. + // The fingerprint method lists are defined below. + function ie11fingerprint(methods) { + var length = getLength(methods); + return function(obj) { + if (obj == null) return false; + // `Map`, `WeakMap` and `Set` have no enumerable keys. + var keys = allKeys(obj); + if (getLength(keys)) return false; + for (var i = 0; i < length; i++) { + if (!isFunction$1(obj[methods[i]])) return false; + } + // If we are testing against `WeakMap`, we need to ensure that + // `obj` doesn't have a `forEach` method in order to distinguish + // it from a regular `Map`. + return methods !== weakMapMethods || !isFunction$1(obj[forEachName]); + }; + } + + // In the interest of compact minification, we write + // each string in the fingerprints only once. + var forEachName = 'forEach', + hasName = 'has', + commonInit = ['clear', 'delete'], + mapTail = ['get', hasName, 'set']; + + // `Map`, `WeakMap` and `Set` each have slightly different + // combinations of the above sublists. + var mapMethods = commonInit.concat(forEachName, mapTail), + weakMapMethods = commonInit.concat(mapTail), + setMethods = ['add'].concat(commonInit, forEachName, hasName); + + var isMap = isIE11 ? ie11fingerprint(mapMethods) : tagTester('Map'); + + var isWeakMap = isIE11 ? ie11fingerprint(weakMapMethods) : tagTester('WeakMap'); + + var isSet = isIE11 ? ie11fingerprint(setMethods) : tagTester('Set'); + + var isWeakSet = tagTester('WeakSet'); + + // Retrieve the values of an object's properties. + function values(obj) { + var _keys = keys(obj); + var length = _keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[_keys[i]]; + } + return values; + } + + // Convert an object into a list of `[key, value]` pairs. + // The opposite of `_.object` with one argument. + function pairs(obj) { + var _keys = keys(obj); + var length = _keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [_keys[i], obj[_keys[i]]]; + } + return pairs; + } + + // Invert the keys and values of an object. The values must be serializable. + function invert(obj) { + var result = {}; + var _keys = keys(obj); + for (var i = 0, length = _keys.length; i < length; i++) { + result[obj[_keys[i]]] = _keys[i]; + } + return result; + } + + // Return a sorted list of the function names available on the object. + function functions(obj) { + var names = []; + for (var key in obj) { + if (isFunction$1(obj[key])) names.push(key); + } + return names.sort(); + } + + // An internal function for creating assigner functions. + function createAssigner(keysFunc, defaults) { + return function(obj) { + var length = arguments.length; + if (defaults) obj = Object(obj); + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + keys = keysFunc(source), + l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (!defaults || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; + }; + } + + // Extend a given object with all the properties in passed-in object(s). + var extend = createAssigner(allKeys); + + // Assigns a given object with all the own properties in the passed-in + // object(s). + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + var extendOwn = createAssigner(keys); + + // Fill in a given object with default properties. + var defaults = createAssigner(allKeys, true); + + // Create a naked function reference for surrogate-prototype-swapping. + function ctor() { + return function(){}; + } + + // An internal function for creating a new object that inherits from another. + function baseCreate(prototype) { + if (!isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + var Ctor = ctor(); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; + } + + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + function create(prototype, props) { + var result = baseCreate(prototype); + if (props) extendOwn(result, props); + return result; + } + + // Create a (shallow-cloned) duplicate of an object. + function clone(obj) { + if (!isObject(obj)) return obj; + return isArray(obj) ? obj.slice() : extend({}, obj); + } + + // Invokes `interceptor` with the `obj` and then returns `obj`. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + function tap(obj, interceptor) { + interceptor(obj); + return obj; + } + + // Normalize a (deep) property `path` to array. + // Like `_.iteratee`, this function can be customized. + function toPath(path) { + return isArray(path) ? path : [path]; + } + _.toPath = toPath; + + // Internal wrapper for `_.toPath` to enable minification. + // Similar to `cb` for `_.iteratee`. + function toPath$1(path) { + return _.toPath(path); + } + + // Internal function to obtain a nested property in `obj` along `path`. + function deepGet(obj, path) { + var length = path.length; + for (var i = 0; i < length; i++) { + if (obj == null) return void 0; + obj = obj[path[i]]; + } + return length ? obj : void 0; + } + + // Get the value of the (deep) property on `path` from `object`. + // If any property in `path` does not exist or if the value is + // `undefined`, return `defaultValue` instead. + // The `path` is normalized through `_.toPath`. + function get(object, path, defaultValue) { + var value = deepGet(object, toPath$1(path)); + return isUndefined(value) ? defaultValue : value; + } + + // Shortcut function for checking if an object has a given property directly on + // itself (in other words, not on a prototype). Unlike the internal `has` + // function, this public version can also traverse nested properties. + function has$1(obj, path) { + path = toPath$1(path); + var length = path.length; + for (var i = 0; i < length; i++) { + var key = path[i]; + if (!has(obj, key)) return false; + obj = obj[key]; + } + return !!length; + } + + // Keep the identity function around for default iteratees. + function identity(value) { + return value; + } + + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + function matcher(attrs) { + attrs = extendOwn({}, attrs); + return function(obj) { + return isMatch(obj, attrs); + }; + } + + // Creates a function that, when passed an object, will traverse that object’s + // properties down the given `path`, specified as an array of keys or indices. + function property(path) { + path = toPath$1(path); + return function(obj) { + return deepGet(obj, path); + }; + } + + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + function optimizeCb(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + // The 2-argument case is omitted because we’re not using it. + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; + } + return function() { + return func.apply(context, arguments); + }; + } + + // An internal function to generate callbacks that can be applied to each + // element in a collection, returning the desired result — either `_.identity`, + // an arbitrary callback, a property matcher, or a property accessor. + function baseIteratee(value, context, argCount) { + if (value == null) return identity; + if (isFunction$1(value)) return optimizeCb(value, context, argCount); + if (isObject(value) && !isArray(value)) return matcher(value); + return property(value); + } + + // External wrapper for our callback generator. Users may customize + // `_.iteratee` if they want additional predicate/iteratee shorthand styles. + // This abstraction hides the internal-only `argCount` argument. + function iteratee(value, context) { + return baseIteratee(value, context, Infinity); + } + _.iteratee = iteratee; + + // The function we call internally to generate a callback. It invokes + // `_.iteratee` if overridden, otherwise `baseIteratee`. + function cb(value, context, argCount) { + if (_.iteratee !== iteratee) return _.iteratee(value, context); + return baseIteratee(value, context, argCount); + } + + // Returns the results of applying the `iteratee` to each element of `obj`. + // In contrast to `_.map` it returns an object. + function mapObject(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var _keys = keys(obj), + length = _keys.length, + results = {}; + for (var index = 0; index < length; index++) { + var currentKey = _keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + } + + // Predicate-generating function. Often useful outside of Underscore. + function noop(){} + + // Generates a function for a given object that returns a given property. + function propertyOf(obj) { + if (obj == null) return noop; + return function(path) { + return get(obj, path); + }; + } + + // Run a function **n** times. + function times(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + } + + // Return a random integer between `min` and `max` (inclusive). + function random(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + } + + // A (possibly faster) way to get the current timestamp as an integer. + var now = Date.now || function() { + return new Date().getTime(); + }; + + // Internal helper to generate functions for escaping and unescaping strings + // to/from HTML interpolation. + function createEscaper(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped. + var source = '(?:' + keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + } + + // Internal list of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + + // Function for escaping strings to HTML interpolation. + var _escape = createEscaper(escapeMap); + + // Internal list of HTML entities for unescaping. + var unescapeMap = invert(escapeMap); + + // Function for unescaping strings from HTML interpolation. + var _unescape = createEscaper(unescapeMap); + + // By default, Underscore uses ERB-style template delimiters. Change the + // following template settings to use alternative delimiters. + var templateSettings = _.templateSettings = { + evaluate: /<%([\s\S]+?)%>/g, + interpolate: /<%=([\s\S]+?)%>/g, + escape: /<%-([\s\S]+?)%>/g + }; + + // When customizing `_.templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g; + + function escapeChar(match) { + return '\\' + escapes[match]; + } + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + function template(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escapeRegExp, escapeChar); + index = offset + match.length; + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + + // Adobe VMs need the match returned to produce the correct offset. + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + var render; + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled source as a convenience for precompilation. + var argument = settings.variable || 'obj'; + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; + } + + // Traverses the children of `obj` along `path`. If a child is a function, it + // is invoked with its parent as context. Returns the value of the final + // child, or `fallback` if any child is undefined. + function result(obj, path, fallback) { + path = toPath$1(path); + var length = path.length; + if (!length) { + return isFunction$1(fallback) ? fallback.call(obj) : fallback; + } + for (var i = 0; i < length; i++) { + var prop = obj == null ? void 0 : obj[path[i]]; + if (prop === void 0) { + prop = fallback; + i = length; // Ensure we don't continue iterating. + } + obj = isFunction$1(prop) ? prop.call(obj) : prop; + } + return obj; + } + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + function uniqueId(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + } + + // Start chaining a wrapped Underscore object. + function chain(obj) { + var instance = _(obj); + instance._chain = true; + return instance; + } + + // Internal function to execute `sourceFunc` bound to `context` with optional + // `args`. Determines whether to execute a function as a constructor or as a + // normal function. + function executeBound(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (isObject(result)) return result; + return self; + } + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. `_` acts + // as a placeholder by default, allowing any combination of arguments to be + // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument. + var partial = restArguments(function(func, boundArgs) { + var placeholder = partial.placeholder; + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }); + + partial.placeholder = _; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). + var bind = restArguments(function(func, context, args) { + if (!isFunction$1(func)) throw new TypeError('Bind must be called on a function'); + var bound = restArguments(function(callArgs) { + return executeBound(func, bound, context, this, args.concat(callArgs)); + }); + return bound; + }); + + // Internal helper for collection methods to determine whether a collection + // should be iterated as an array or as an object. + // Related: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var isArrayLike = createSizePropertyCheck(getLength); + + // Internal implementation of a recursive `flatten` function. + function flatten(input, depth, strict, output) { + output = output || []; + if (!depth && depth !== 0) { + depth = Infinity; + } else if (depth <= 0) { + return output.concat(input); + } + var idx = output.length; + for (var i = 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (isArray(value) || isArguments$1(value))) { + // Flatten current level of array or arguments object. + if (depth > 1) { + flatten(value, depth - 1, strict, output); + idx = output.length; + } else { + var j = 0, len = value.length; + while (j < len) output[idx++] = value[j++]; + } + } else if (!strict) { + output[idx++] = value; + } + } + return output; + } + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + var bindAll = restArguments(function(obj, keys) { + keys = flatten(keys, false, false); + var index = keys.length; + if (index < 1) throw new Error('bindAll must be passed function names'); + while (index--) { + var key = keys[index]; + obj[key] = bind(obj[key], obj); + } + return obj; + }); + + // Memoize an expensive function by storing its results. + function memoize(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!has(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + } + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + var delay = restArguments(function(func, wait, args) { + return setTimeout(function() { + return func.apply(null, args); + }, wait); + }); + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + var defer = partial(delay, _, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + function throttle(func, wait, options) { + var timeout, context, args, result; + var previous = 0; + if (!options) options = {}; + + var later = function() { + previous = options.leading === false ? 0 : now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + + var throttled = function() { + var _now = now(); + if (!previous && options.leading === false) previous = _now; + var remaining = wait - (_now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = _now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + + throttled.cancel = function() { + clearTimeout(timeout); + previous = 0; + timeout = context = args = null; + }; + + return throttled; + } + + // When a sequence of calls of the returned function ends, the argument + // function is triggered. The end of a sequence is defined by the `wait` + // parameter. If `immediate` is passed, the argument function will be + // triggered at the beginning of the sequence instead of at the end. + function debounce(func, wait, immediate) { + var timeout, previous, args, result, context; + + var later = function() { + var passed = now() - previous; + if (wait > passed) { + timeout = setTimeout(later, wait - passed); + } else { + timeout = null; + if (!immediate) result = func.apply(context, args); + // This check is needed because `func` can recursively invoke `debounced`. + if (!timeout) args = context = null; + } + }; + + var debounced = restArguments(function(_args) { + context = this; + args = _args; + previous = now(); + if (!timeout) { + timeout = setTimeout(later, wait); + if (immediate) result = func.apply(context, args); + } + return result; + }); + + debounced.cancel = function() { + clearTimeout(timeout); + timeout = args = context = null; + }; + + return debounced; + } + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + function wrap(func, wrapper) { + return partial(wrapper, func); + } + + // Returns a negated version of the passed-in predicate. + function negate(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + } + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + function compose() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; + }; + } + + // Returns a function that will only be executed on and after the Nth call. + function after(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + } + + // Returns a function that will only be executed up to (but not including) the + // Nth call. + function before(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; + } + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + var once = partial(before, 2); + + // Returns the first key on an object that passes a truth test. + function findKey(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = keys(obj), key; + for (var i = 0, length = _keys.length; i < length; i++) { + key = _keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + } + + // Internal function to generate `_.findIndex` and `_.findLastIndex`. + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } + + // Returns the first index on an array-like that passes a truth test. + var findIndex = createPredicateIndexFinder(1); + + // Returns the last index on an array-like that passes a truth test. + var findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + function sortedIndex(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; + } + + // Internal function to generate the `_.indexOf` and `_.lastIndexOf` functions. + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), isNaN$1); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } + + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + var indexOf = createIndexFinder(1, findIndex, sortedIndex); + + // Return the position of the last occurrence of an item in an array, + // or -1 if the item is not included in the array. + var lastIndexOf = createIndexFinder(-1, findLastIndex); + + // Return the first value which passes a truth test. + function find(obj, predicate, context) { + var keyFinder = isArrayLike(obj) ? findIndex : findKey; + var key = keyFinder(obj, predicate, context); + if (key !== void 0 && key !== -1) return obj[key]; + } + + // Convenience version of a common use case of `_.find`: getting the first + // object containing specific `key:value` pairs. + function findWhere(obj, attrs) { + return find(obj, matcher(attrs)); + } + + // The cornerstone for collection functions, an `each` + // implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + function each(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var _keys = keys(obj); + for (i = 0, length = _keys.length; i < length; i++) { + iteratee(obj[_keys[i]], _keys[i], obj); + } + } + return obj; + } + + // Return the results of applying the iteratee to each element. + function map(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + } + + // Internal helper to create a reducing function, iterating left or right. + function createReduce(dir) { + // Wrap code that reassigns argument variables in a separate function than + // the one that accesses `arguments.length` to avoid a perf hit. (#1991) + var reducer = function(obj, iteratee, memo, initial) { + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length, + index = dir > 0 ? 0 : length - 1; + if (!initial) { + memo = obj[_keys ? _keys[index] : index]; + index += dir; + } + for (; index >= 0 && index < length; index += dir) { + var currentKey = _keys ? _keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + }; + + return function(obj, iteratee, memo, context) { + var initial = arguments.length >= 3; + return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial); + }; + } + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + var reduce = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + var reduceRight = createReduce(-1); + + // Return all the elements that pass a truth test. + function filter(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + } + + // Return all the elements for which a truth test fails. + function reject(obj, predicate, context) { + return filter(obj, negate(cb(predicate)), context); + } + + // Determine whether all of the elements pass a truth test. + function every(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; + } + return true; + } + + // Determine if at least one element in the object passes a truth test. + function some(obj, predicate, context) { + predicate = cb(predicate, context); + var _keys = !isArrayLike(obj) && keys(obj), + length = (_keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = _keys ? _keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; + } + return false; + } + + // Determine if the array or object contains a given item (using `===`). + function contains(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return indexOf(obj, item, fromIndex) >= 0; + } + + // Invoke a method (with arguments) on every item in a collection. + var invoke = restArguments(function(obj, path, args) { + var contextPath, func; + if (isFunction$1(path)) { + func = path; + } else { + path = toPath$1(path); + contextPath = path.slice(0, -1); + path = path[path.length - 1]; + } + return map(obj, function(context) { + var method = func; + if (!method) { + if (contextPath && contextPath.length) { + context = deepGet(context, contextPath); + } + if (context == null) return void 0; + method = context[path]; + } + return method == null ? method : method.apply(context, args); + }); + }); + + // Convenience version of a common use case of `_.map`: fetching a property. + function pluck(obj, key) { + return map(obj, property(key)); + } + + // Convenience version of a common use case of `_.filter`: selecting only + // objects containing specific `key:value` pairs. + function where(obj, attrs) { + return filter(obj, matcher(attrs)); + } + + // Return the maximum element (or element-based computation). + function max(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) { + obj = isArrayLike(obj) ? obj : values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value != null && value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + each(obj, function(v, index, list) { + computed = iteratee(v, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = v; + lastComputed = computed; + } + }); + } + return result; + } + + // Return the minimum element (or element-based computation). + function min(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) { + obj = isArrayLike(obj) ? obj : values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value != null && value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + each(obj, function(v, index, list) { + computed = iteratee(v, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = v; + lastComputed = computed; + } + }); + } + return result; + } + + // Sample **n** random values from a collection using the modern version of the + // [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `_.map`. + function sample(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = values(obj); + return obj[random(obj.length - 1)]; + } + var sample = isArrayLike(obj) ? clone(obj) : values(obj); + var length = getLength(sample); + n = Math.max(Math.min(n, length), 0); + var last = length - 1; + for (var index = 0; index < n; index++) { + var rand = random(index, last); + var temp = sample[index]; + sample[index] = sample[rand]; + sample[rand] = temp; + } + return sample.slice(0, n); + } + + // Shuffle a collection. + function shuffle(obj) { + return sample(obj, Infinity); + } + + // Sort the object's values by a criterion produced by an iteratee. + function sortBy(obj, iteratee, context) { + var index = 0; + iteratee = cb(iteratee, context); + return pluck(map(obj, function(value, key, list) { + return { + value: value, + index: index++, + criteria: iteratee(value, key, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + } + + // An internal function used for aggregate "group by" operations. + function group(behavior, partition) { + return function(obj, iteratee, context) { + var result = partition ? [[], []] : {}; + iteratee = cb(iteratee, context); + each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + } + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + var groupBy = group(function(result, value, key) { + if (has(result, key)) result[key].push(value); else result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `_.groupBy`, but for + // when you know that your index values will be unique. + var indexBy = group(function(result, value, key) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + var countBy = group(function(result, value, key) { + if (has(result, key)) result[key]++; else result[key] = 1; + }); + + // Split a collection into two arrays: one whose elements all pass the given + // truth test, and one whose elements all do not pass the truth test. + var partition = group(function(result, value, pass) { + result[pass ? 0 : 1].push(value); + }, true); + + // Safely create a real, live array from anything iterable. + var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g; + function toArray(obj) { + if (!obj) return []; + if (isArray(obj)) return slice.call(obj); + if (isString(obj)) { + // Keep surrogate pair characters together. + return obj.match(reStrSymbol); + } + if (isArrayLike(obj)) return map(obj, identity); + return values(obj); + } + + // Return the number of elements in a collection. + function size(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : keys(obj).length; + } + + // Internal `_.pick` helper function to determine whether `key` is an enumerable + // property name of `obj`. + function keyInObj(value, key, obj) { + return key in obj; + } + + // Return a copy of the object only containing the allowed properties. + var pick = restArguments(function(obj, keys) { + var result = {}, iteratee = keys[0]; + if (obj == null) return result; + if (isFunction$1(iteratee)) { + if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]); + keys = allKeys(obj); + } else { + iteratee = keyInObj; + keys = flatten(keys, false, false); + obj = Object(obj); + } + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }); + + // Return a copy of the object without the disallowed properties. + var omit = restArguments(function(obj, keys) { + var iteratee = keys[0], context; + if (isFunction$1(iteratee)) { + iteratee = negate(iteratee); + if (keys.length > 1) context = keys[1]; + } else { + keys = map(flatten(keys, false, false), String); + iteratee = function(value, key) { + return !contains(keys, key); + }; + } + return pick(obj, iteratee, context); + }); + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + function initial(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + } + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. The **guard** check allows it to work with `_.map`. + function first(array, n, guard) { + if (array == null || array.length < 1) return n == null || guard ? void 0 : []; + if (n == null || guard) return array[0]; + return initial(array, array.length - n); + } + + // Returns everything but the first entry of the `array`. Especially useful on + // the `arguments` object. Passing an **n** will return the rest N values in the + // `array`. + function rest(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + } + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + function last(array, n, guard) { + if (array == null || array.length < 1) return n == null || guard ? void 0 : []; + if (n == null || guard) return array[array.length - 1]; + return rest(array, Math.max(0, array.length - n)); + } + + // Trim out all falsy values from an array. + function compact(array) { + return filter(array, Boolean); + } + + // Flatten out an array, either recursively (by default), or up to `depth`. + // Passing `true` or `false` as `depth` means `1` or `Infinity`, respectively. + function flatten$1(array, depth) { + return flatten(array, depth, false); + } + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + var difference = restArguments(function(array, rest) { + rest = flatten(rest, true, true); + return filter(array, function(value){ + return !contains(rest, value); + }); + }); + + // Return a version of the array that does not contain the specified value(s). + var without = restArguments(function(array, otherArrays) { + return difference(array, otherArrays); + }); + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // The faster algorithm will not work with an iteratee if the iteratee + // is not a one-to-one function, so providing an iteratee will disable + // the faster algorithm. + function uniq(array, isSorted, iteratee, context) { + if (!isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted && !iteratee) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!contains(seen, computed)) { + seen.push(computed); + result.push(value); + } + } else if (!contains(result, value)) { + result.push(value); + } + } + return result; + } + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + var union = restArguments(function(arrays) { + return uniq(flatten(arrays, true, true)); + }); + + // Produce an array that contains every item shared between all the + // passed-in arrays. + function intersection(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (contains(result, item)) continue; + var j; + for (j = 1; j < argsLength; j++) { + if (!contains(arguments[j], item)) break; + } + if (j === argsLength) result.push(item); + } + return result; + } + + // Complement of zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices. + function unzip(array) { + var length = array && max(array, getLength).length || 0; + var result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = pluck(array, index); + } + return result; + } + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + var zip = restArguments(unzip); + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. Passing by pairs is the reverse of `_.pairs`. + function object(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + } + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](https://docs.python.org/library/functions.html#range). + function range(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; + } + if (!step) { + step = stop < start ? -1 : 1; + } + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; + } + + return range; + } + + // Chunk a single array into multiple arrays, each containing `count` or fewer + // items. + function chunk(array, count) { + if (count == null || count < 1) return []; + var result = []; + var i = 0, length = array.length; + while (i < length) { + result.push(slice.call(array, i, i += count)); + } + return result; + } + + // Helper function to continue chaining intermediate results. + function chainResult(instance, obj) { + return instance._chain ? _(obj).chain() : obj; + } + + // Add your own custom functions to the Underscore object. + function mixin(obj) { + each(functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return chainResult(this, func.apply(_, args)); + }; + }); + return _; + } + + // Add all mutator `Array` functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + if (obj != null) { + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) { + delete obj[0]; + } + } + return chainResult(this, obj); + }; + }); + + // Add all accessor `Array` functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + if (obj != null) obj = method.apply(obj, arguments); + return chainResult(this, obj); + }; + }); + + // Named Exports + + var allExports = { + __proto__: null, + VERSION: VERSION, + restArguments: restArguments, + isObject: isObject, + isNull: isNull, + isUndefined: isUndefined, + isBoolean: isBoolean, + isElement: isElement, + isString: isString, + isNumber: isNumber, + isDate: isDate, + isRegExp: isRegExp, + isError: isError, + isSymbol: isSymbol, + isArrayBuffer: isArrayBuffer, + isDataView: isDataView$1, + isArray: isArray, + isFunction: isFunction$1, + isArguments: isArguments$1, + isFinite: isFinite$1, + isNaN: isNaN$1, + isTypedArray: isTypedArray$1, + isEmpty: isEmpty, + isMatch: isMatch, + isEqual: isEqual, + isMap: isMap, + isWeakMap: isWeakMap, + isSet: isSet, + isWeakSet: isWeakSet, + keys: keys, + allKeys: allKeys, + values: values, + pairs: pairs, + invert: invert, + functions: functions, + methods: functions, + extend: extend, + extendOwn: extendOwn, + assign: extendOwn, + defaults: defaults, + create: create, + clone: clone, + tap: tap, + get: get, + has: has$1, + mapObject: mapObject, + identity: identity, + constant: constant, + noop: noop, + toPath: toPath, + property: property, + propertyOf: propertyOf, + matcher: matcher, + matches: matcher, + times: times, + random: random, + now: now, + escape: _escape, + unescape: _unescape, + templateSettings: templateSettings, + template: template, + result: result, + uniqueId: uniqueId, + chain: chain, + iteratee: iteratee, + partial: partial, + bind: bind, + bindAll: bindAll, + memoize: memoize, + delay: delay, + defer: defer, + throttle: throttle, + debounce: debounce, + wrap: wrap, + negate: negate, + compose: compose, + after: after, + before: before, + once: once, + findKey: findKey, + findIndex: findIndex, + findLastIndex: findLastIndex, + sortedIndex: sortedIndex, + indexOf: indexOf, + lastIndexOf: lastIndexOf, + find: find, + detect: find, + findWhere: findWhere, + each: each, + forEach: each, + map: map, + collect: map, + reduce: reduce, + foldl: reduce, + inject: reduce, + reduceRight: reduceRight, + foldr: reduceRight, + filter: filter, + select: filter, + reject: reject, + every: every, + all: every, + some: some, + any: some, + contains: contains, + includes: contains, + include: contains, + invoke: invoke, + pluck: pluck, + where: where, + max: max, + min: min, + shuffle: shuffle, + sample: sample, + sortBy: sortBy, + groupBy: groupBy, + indexBy: indexBy, + countBy: countBy, + partition: partition, + toArray: toArray, + size: size, + pick: pick, + omit: omit, + first: first, + head: first, + take: first, + initial: initial, + last: last, + rest: rest, + tail: rest, + drop: rest, + compact: compact, + flatten: flatten$1, + without: without, + uniq: uniq, + unique: uniq, + union: union, + intersection: intersection, + difference: difference, + unzip: unzip, + transpose: unzip, + zip: zip, + object: object, + range: range, + chunk: chunk, + mixin: mixin, + 'default': _ + }; + + // Default Export + + // Add all of the Underscore functions to the wrapper object. + var _$1 = mixin(allExports); + // Legacy Node.js API. + _$1._ = _$1; + + return _$1; + +}))); +//# sourceMappingURL=underscore.js.map diff --git a/sphinx/themes/basic/static/underscore-1.3.1.js b/sphinx/themes/basic/static/underscore-1.3.1.js deleted file mode 100644 index 208d4cd89..000000000 --- a/sphinx/themes/basic/static/underscore-1.3.1.js +++ /dev/null @@ -1,999 +0,0 @@ -// Underscore.js 1.3.1 -// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore is freely distributable under the MIT license. -// Portions of Underscore are inspired or borrowed from Prototype, -// Oliver Steele's Functional, and John Resig's Micro-Templating. -// For all details and documentation: -// http://documentcloud.github.com/underscore - -(function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Establish the object that gets returned to break out of a loop iteration. - var breaker = {}; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var slice = ArrayProto.slice, - unshift = ArrayProto.unshift, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeForEach = ArrayProto.forEach, - nativeMap = ArrayProto.map, - nativeReduce = ArrayProto.reduce, - nativeReduceRight = ArrayProto.reduceRight, - nativeFilter = ArrayProto.filter, - nativeEvery = ArrayProto.every, - nativeSome = ArrayProto.some, - nativeIndexOf = ArrayProto.indexOf, - nativeLastIndexOf = ArrayProto.lastIndexOf, - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { return new wrapper(obj); }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object via a string identifier, - // for Closure Compiler "advanced" mode. - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } else { - root['_'] = _; - } - - // Current version. - _.VERSION = '1.3.1'; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles objects with the built-in `forEach`, arrays, and raw objects. - // Delegates to **ECMAScript 5**'s native `forEach` if available. - var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return; - if (nativeForEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - for (var key in obj) { - if (_.has(obj, key)) { - if (iterator.call(context, obj[key], key, obj) === breaker) return; - } - } - } - }; - - // Return the results of applying the iterator to each element. - // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = _.collect = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); - each(obj, function(value, index, list) { - results[results.length] = iterator.call(context, value, index, list); - }); - if (obj.length === +obj.length) results.length = obj.length; - return results; - }; - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. - _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduce && obj.reduce === nativeReduce) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); - } - each(obj, function(value, index, list) { - if (!initial) { - memo = value; - initial = true; - } else { - memo = iterator.call(context, memo, value, index, list); - } - }); - if (!initial) throw new TypeError('Reduce of empty array with no initial value'); - return memo; - }; - - // The right-associative version of reduce, also known as `foldr`. - // Delegates to **ECMAScript 5**'s native `reduceRight` if available. - _.reduceRight = _.foldr = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); - } - var reversed = _.toArray(obj).reverse(); - if (context && !initial) iterator = _.bind(iterator, context); - return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); - }; - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, iterator, context) { - var result; - any(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) { - result = value; - return true; - } - }); - return result; - }; - - // Return all the elements that pass a truth test. - // Delegates to **ECMAScript 5**'s native `filter` if available. - // Aliased as `select`. - _.filter = _.select = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); - each(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - each(obj, function(value, index, list) { - if (!iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Determine whether all of the elements match a truth test. - // Delegates to **ECMAScript 5**'s native `every` if available. - // Aliased as `all`. - _.every = _.all = function(obj, iterator, context) { - var result = true; - if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); - each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) return breaker; - }); - return result; - }; - - // Determine if at least one element in the object matches a truth test. - // Delegates to **ECMAScript 5**'s native `some` if available. - // Aliased as `any`. - var any = _.some = _.any = function(obj, iterator, context) { - iterator || (iterator = _.identity); - var result = false; - if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); - each(obj, function(value, index, list) { - if (result || (result = iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if a given value is included in the array or object using `===`. - // Aliased as `contains`. - _.include = _.contains = function(obj, target) { - var found = false; - if (obj == null) return found; - if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - found = any(obj, function(value) { - return value === target; - }); - return found; - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - return _.map(obj, function(value) { - return (_.isFunction(method) ? method || value : value[method]).apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, function(value){ return value[key]; }); - }; - - // Return the maximum element or (element-based computation). - _.max = function(obj, iterator, context) { - if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); - if (!iterator && _.isEmpty(obj)) return -Infinity; - var result = {computed : -Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed >= result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iterator, context) { - if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); - if (!iterator && _.isEmpty(obj)) return Infinity; - var result = {computed : Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed < result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Shuffle an array. - _.shuffle = function(obj) { - var shuffled = [], rand; - each(obj, function(value, index, list) { - if (index == 0) { - shuffled[0] = value; - } else { - rand = Math.floor(Math.random() * (index + 1)); - shuffled[index] = shuffled[rand]; - shuffled[rand] = value; - } - }); - return shuffled; - }; - - // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, iterator, context) { - return _.pluck(_.map(obj, function(value, index, list) { - return { - value : value, - criteria : iterator.call(context, value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }), 'value'); - }; - - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = function(obj, val) { - var result = {}; - var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; - each(obj, function(value, index) { - var key = iterator(value, index); - (result[key] || (result[key] = [])).push(value); - }); - return result; - }; - - // Use a comparator function to figure out at what index an object should - // be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iterator) { - iterator || (iterator = _.identity); - var low = 0, high = array.length; - while (low < high) { - var mid = (low + high) >> 1; - iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; - } - return low; - }; - - // Safely convert anything iterable into a real, live array. - _.toArray = function(iterable) { - if (!iterable) return []; - if (iterable.toArray) return iterable.toArray(); - if (_.isArray(iterable)) return slice.call(iterable); - if (_.isArguments(iterable)) return slice.call(iterable); - return _.values(iterable); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - return _.toArray(obj).length; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head`. The **guard** check allows it to work - // with `_.map`. - _.first = _.head = function(array, n, guard) { - return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; - }; - - // Returns everything but the last entry of the array. Especcialy useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. The **guard** check allows it to work with - // `_.map`. - _.initial = function(array, n, guard) { - return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); - }; - - // Get the last element of an array. Passing **n** will return the last N - // values in the array. The **guard** check allows it to work with `_.map`. - _.last = function(array, n, guard) { - if ((n != null) && !guard) { - return slice.call(array, Math.max(array.length - n, 0)); - } else { - return array[array.length - 1]; - } - }; - - // Returns everything but the first entry of the array. Aliased as `tail`. - // Especially useful on the arguments object. Passing an **index** will return - // the rest of the values in the array from that index onward. The **guard** - // check allows it to work with `_.map`. - _.rest = _.tail = function(array, index, guard) { - return slice.call(array, (index == null) || guard ? 1 : index); - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, function(value){ return !!value; }); - }; - - // Return a completely flattened version of an array. - _.flatten = function(array, shallow) { - return _.reduce(array, function(memo, value) { - if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); - memo[memo.length] = value; - return memo; - }, []); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iterator) { - var initial = iterator ? _.map(array, iterator) : array; - var result = []; - _.reduce(initial, function(memo, el, i) { - if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { - memo[memo.length] = el; - result[result.length] = array[i]; - } - return memo; - }, []); - return result; - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(_.flatten(arguments, true)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. (Aliased as "intersect" for back-compat.) - _.intersection = _.intersect = function(array) { - var rest = slice.call(arguments, 1); - return _.filter(_.uniq(array), function(item) { - return _.every(rest, function(other) { - return _.indexOf(other, item) >= 0; - }); - }); - }; - - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = _.flatten(slice.call(arguments, 1)); - return _.filter(array, function(value){ return !_.include(rest, value); }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - var args = slice.call(arguments); - var length = _.max(_.pluck(args, 'length')); - var results = new Array(length); - for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); - return results; - }; - - // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), - // we need this function. Return the position of the first occurrence of an - // item in an array, or -1 if the item is not included in the array. - // Delegates to **ECMAScript 5**'s native `indexOf` if available. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = function(array, item, isSorted) { - if (array == null) return -1; - var i, l; - if (isSorted) { - i = _.sortedIndex(array, item); - return array[i] === item ? i : -1; - } - if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); - for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i; - return -1; - }; - - // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. - _.lastIndexOf = function(array, item) { - if (array == null) return -1; - if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); - var i = array.length; - while (i--) if (i in array && array[i] === item) return i; - return -1; - }; - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (arguments.length <= 1) { - stop = start || 0; - start = 0; - } - step = arguments[2] || 1; - - var len = Math.max(Math.ceil((stop - start) / step), 0); - var idx = 0; - var range = new Array(len); - - while(idx < len) { - range[idx++] = start; - start += step; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Reusable constructor function for prototype setting. - var ctor = function(){}; - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Binding with arguments is also known as `curry`. - // Delegates to **ECMAScript 5**'s native `Function.bind` if available. - // We check for `func.bind` first, to fail fast when `func` is undefined. - _.bind = function bind(func, context) { - var bound, args; - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - if (!_.isFunction(func)) throw new TypeError; - args = slice.call(arguments, 2); - return bound = function() { - if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); - ctor.prototype = func.prototype; - var self = new ctor; - var result = func.apply(self, args.concat(slice.call(arguments))); - if (Object(result) === result) return result; - return self; - }; - }; - - // Bind all of an object's methods to that object. Useful for ensuring that - // all callbacks defined on an object belong to it. - _.bindAll = function(obj) { - var funcs = slice.call(arguments, 1); - if (funcs.length == 0) funcs = _.functions(obj); - each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memo = {}; - hasher || (hasher = _.identity); - return function() { - var key = hasher.apply(this, arguments); - return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); - }; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ return func.apply(func, args); }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); - }; - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. - _.throttle = function(func, wait) { - var context, args, timeout, throttling, more; - var whenDone = _.debounce(function(){ more = throttling = false; }, wait); - return function() { - context = this; args = arguments; - var later = function() { - timeout = null; - if (more) func.apply(context, args); - whenDone(); - }; - if (!timeout) timeout = setTimeout(later, wait); - if (throttling) { - more = true; - } else { - func.apply(context, args); - } - whenDone(); - throttling = true; - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. - _.debounce = function(func, wait) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - func.apply(context, args); - }; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = function(func) { - var ran = false, memo; - return function() { - if (ran) return memo; - ran = true; - return memo = func.apply(this, arguments); - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return function() { - var args = [func].concat(slice.call(arguments, 0)); - return wrapper.apply(this, args); - }; - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var funcs = arguments; - return function() { - var args = arguments; - for (var i = funcs.length - 1; i >= 0; i--) { - args = [funcs[i].apply(this, args)]; - } - return args[0]; - }; - }; - - // Returns a function that will only be executed after being called N times. - _.after = function(times, func) { - if (times <= 0) return func(); - return function() { - if (--times < 1) { return func.apply(this, arguments); } - }; - }; - - // Object Functions - // ---------------- - - // Retrieve the names of an object's properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = nativeKeys || function(obj) { - if (obj !== Object(obj)) throw new TypeError('Invalid object'); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - return _.map(obj, _.identity); - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = function(obj) { - each(slice.call(arguments, 1), function(source) { - for (var prop in source) { - obj[prop] = source[prop]; - } - }); - return obj; - }; - - // Fill in a given object with default properties. - _.defaults = function(obj) { - each(slice.call(arguments, 1), function(source) { - for (var prop in source) { - if (obj[prop] == null) obj[prop] = source[prop]; - } - }); - return obj; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Internal recursive comparison function. - function eq(a, b, stack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. - if (a === b) return a !== 0 || 1 / a == 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a._chain) a = a._wrapped; - if (b._chain) b = b._wrapped; - // Invoke a custom `isEqual` method if one is provided. - if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b); - if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a); - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className != toString.call(b)) return false; - switch (className) { - // Strings, numbers, dates, and booleans are compared by value. - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return a == String(b); - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for - // other numeric values. - return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a == +b; - // RegExps are compared by their source patterns and flags. - case '[object RegExp]': - return a.source == b.source && - a.global == b.global && - a.multiline == b.multiline && - a.ignoreCase == b.ignoreCase; - } - if (typeof a != 'object' || typeof b != 'object') return false; - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - var length = stack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (stack[length] == a) return true; - } - // Add the first object to the stack of traversed objects. - stack.push(a); - var size = 0, result = true; - // Recursively compare objects and arrays. - if (className == '[object Array]') { - // Compare array lengths to determine if a deep comparison is necessary. - size = a.length; - result = size == b.length; - if (result) { - // Deep compare the contents, ignoring non-numeric properties. - while (size--) { - // Ensure commutative equality for sparse arrays. - if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break; - } - } - } else { - // Objects with different constructors are not equivalent. - if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; - // Deep compare objects. - for (var key in a) { - if (_.has(a, key)) { - // Count the expected number of properties. - size++; - // Deep compare each member. - if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break; - } - } - // Ensure that both objects contain the same number of properties. - if (result) { - for (key in b) { - if (_.has(b, key) && !(size--)) break; - } - result = !size; - } - } - // Remove the first object from the stack of traversed objects. - stack.pop(); - return result; - } - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b, []); - }; - - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; - for (var key in obj) if (_.has(obj, key)) return false; - return true; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType == 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) == '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - return obj === Object(obj); - }; - - // Is a given variable an arguments object? - _.isArguments = function(obj) { - return toString.call(obj) == '[object Arguments]'; - }; - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return !!(obj && _.has(obj, 'callee')); - }; - } - - // Is a given value a function? - _.isFunction = function(obj) { - return toString.call(obj) == '[object Function]'; - }; - - // Is a given value a string? - _.isString = function(obj) { - return toString.call(obj) == '[object String]'; - }; - - // Is a given value a number? - _.isNumber = function(obj) { - return toString.call(obj) == '[object Number]'; - }; - - // Is the given value `NaN`? - _.isNaN = function(obj) { - // `NaN` is the only value for which `===` is not reflexive. - return obj !== obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; - }; - - // Is a given value a date? - _.isDate = function(obj) { - return toString.call(obj) == '[object Date]'; - }; - - // Is the given value a regular expression? - _.isRegExp = function(obj) { - return toString.call(obj) == '[object RegExp]'; - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Has own property? - _.has = function(obj, key) { - return hasOwnProperty.call(obj, key); - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iterators. - _.identity = function(value) { - return value; - }; - - // Run a function **n** times. - _.times = function (n, iterator, context) { - for (var i = 0; i < n; i++) iterator.call(context, i); - }; - - // Escape a string for HTML interpolation. - _.escape = function(string) { - return (''+string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); - }; - - // Add your own custom functions to the Underscore object, ensuring that - // they're correctly added to the OOP wrapper as well. - _.mixin = function(obj) { - each(_.functions(obj), function(name){ - addToWrapper(name, _[name] = obj[name]); - }); - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = idCounter++; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; - - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /.^/; - - // Within an interpolation, evaluation, or escaping, remove HTML escaping - // that had been previously added. - var unescape = function(code) { - return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'"); - }; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - _.template = function(str, data) { - var c = _.templateSettings; - var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + - 'with(obj||{}){__p.push(\'' + - str.replace(/\\/g, '\\\\') - .replace(/'/g, "\\'") - .replace(c.escape || noMatch, function(match, code) { - return "',_.escape(" + unescape(code) + "),'"; - }) - .replace(c.interpolate || noMatch, function(match, code) { - return "'," + unescape(code) + ",'"; - }) - .replace(c.evaluate || noMatch, function(match, code) { - return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('"; - }) - .replace(/\r/g, '\\r') - .replace(/\n/g, '\\n') - .replace(/\t/g, '\\t') - + "');}return __p.join('');"; - var func = new Function('obj', '_', tmpl); - if (data) return func(data, _); - return function(data) { - return func.call(this, data, _); - }; - }; - - // Add a "chain" function, which will delegate to the wrapper. - _.chain = function(obj) { - return _(obj).chain(); - }; - - // The OOP Wrapper - // --------------- - - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - var wrapper = function(obj) { this._wrapped = obj; }; - - // Expose `wrapper.prototype` as `_.prototype` - _.prototype = wrapper.prototype; - - // Helper function to continue chaining intermediate results. - var result = function(obj, chain) { - return chain ? _(obj).chain() : obj; - }; - - // A method to easily add functions to the OOP wrapper. - var addToWrapper = function(name, func) { - wrapper.prototype[name] = function() { - var args = slice.call(arguments); - unshift.call(args, this._wrapped); - return result(func.apply(_, args), this._chain); - }; - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - wrapper.prototype[name] = function() { - var wrapped = this._wrapped; - method.apply(wrapped, arguments); - var length = wrapped.length; - if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; - return result(wrapped, this._chain); - }; - }); - - // Add all accessor Array functions to the wrapper. - each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - wrapper.prototype[name] = function() { - return result(method.apply(this._wrapped, arguments), this._chain); - }; - }); - - // Start chaining a wrapped Underscore object. - wrapper.prototype.chain = function() { - this._chain = true; - return this; - }; - - // Extracts the result from a wrapped and chained object. - wrapper.prototype.value = function() { - return this._wrapped; - }; - -}).call(this); diff --git a/sphinx/themes/basic/static/underscore.js b/sphinx/themes/basic/static/underscore.js index 5b55f32be..166240ef2 100644 --- a/sphinx/themes/basic/static/underscore.js +++ b/sphinx/themes/basic/static/underscore.js @@ -1,31 +1,6 @@ -// Underscore.js 1.3.1 -// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore is freely distributable under the MIT license. -// Portions of Underscore are inspired or borrowed from Prototype, -// Oliver Steele's Functional, and John Resig's Micro-Templating. -// For all details and documentation: -// http://documentcloud.github.com/underscore -(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== -c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c, -h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each= -b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a== -null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect= -function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e= -e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck= -function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})}); -return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a, -c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest= -b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]); -return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c, -d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g}; -var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a, -c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true: -a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}}; -b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments, -1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)}; -b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"}; -b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a), -function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+ -u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]= -function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain= -true;return this};m.prototype.value=function(){return this._wrapped}}).call(this); +!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define("underscore",r):(n=n||self,function(){var t=n._,e=n._=r();e.noConflict=function(){return n._=t,e}}())}(this,(function(){ +// Underscore.js 1.12.0 +// https://underscorejs.org +// (c) 2009-2020 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. +var n="1.12.0",r="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||Function("return this")()||{},t=Array.prototype,e=Object.prototype,u="undefined"!=typeof Symbol?Symbol.prototype:null,o=t.push,i=t.slice,a=e.toString,f=e.hasOwnProperty,c="undefined"!=typeof ArrayBuffer,l="undefined"!=typeof DataView,s=Array.isArray,p=Object.keys,v=Object.create,h=c&&ArrayBuffer.isView,y=isNaN,g=isFinite,d=!{toString:null}.propertyIsEnumerable("toString"),b=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],m=Math.pow(2,53)-1;function j(n,r){return r=null==r?n.length-1:+r,function(){for(var t=Math.max(arguments.length-r,0),e=Array(t),u=0;u<t;u++)e[u]=arguments[u+r];switch(r){case 0:return n.call(this,e);case 1:return n.call(this,arguments[0],e);case 2:return n.call(this,arguments[0],arguments[1],e)}var o=Array(r+1);for(u=0;u<r;u++)o[u]=arguments[u];return o[r]=e,n.apply(this,o)}}function _(n){var r=typeof n;return"function"===r||"object"===r&&!!n}function w(n){return void 0===n}function A(n){return!0===n||!1===n||"[object Boolean]"===a.call(n)}function x(n){var r="[object "+n+"]";return function(n){return a.call(n)===r}}var S=x("String"),O=x("Number"),M=x("Date"),E=x("RegExp"),B=x("Error"),N=x("Symbol"),I=x("ArrayBuffer"),k=x("Function"),T=r.document&&r.document.childNodes;"function"!=typeof/./&&"object"!=typeof Int8Array&&"function"!=typeof T&&(k=function(n){return"function"==typeof n||!1});var D=k,R=x("Object"),F=l&&R(new DataView(new ArrayBuffer(8))),V="undefined"!=typeof Map&&R(new Map),P=x("DataView");var q=F?function(n){return null!=n&&D(n.getInt8)&&I(n.buffer)}:P,U=s||x("Array");function W(n,r){return null!=n&&f.call(n,r)}var z=x("Arguments");!function(){z(arguments)||(z=function(n){return W(n,"callee")})}();var L=z;function C(n){return O(n)&&y(n)}function K(n){return function(){return n}}function J(n){return function(r){var t=n(r);return"number"==typeof t&&t>=0&&t<=m}}function $(n){return function(r){return null==r?void 0:r[n]}}var G=$("byteLength"),H=J(G),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var X=c?function(n){return h?h(n)&&!q(n):H(n)&&Q.test(a.call(n))}:K(!1),Y=$("length");function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e<t;++e)r[n[e]]=!0;return{contains:function(n){return r[n]},push:function(t){return r[t]=!0,n.push(t)}}}(r);var t=b.length,u=n.constructor,o=D(u)&&u.prototype||e,i="constructor";for(W(n,i)&&!r.contains(i)&&r.push(i);t--;)(i=b[t])in n&&n[i]!==o[i]&&!r.contains(i)&&r.push(i)}function nn(n){if(!_(n))return[];if(p)return p(n);var r=[];for(var t in n)W(n,t)&&r.push(t);return d&&Z(n,r),r}function rn(n,r){var t=nn(r),e=t.length;if(null==n)return!e;for(var u=Object(n),o=0;o<e;o++){var i=t[o];if(r[i]!==u[i]||!(i in u))return!1}return!0}function tn(n){return n instanceof tn?n:this instanceof tn?void(this._wrapped=n):new tn(n)}function en(n){return new Uint8Array(n.buffer||n,n.byteOffset||0,G(n))}tn.VERSION=n,tn.prototype.value=function(){return this._wrapped},tn.prototype.valueOf=tn.prototype.toJSON=tn.prototype.value,tn.prototype.toString=function(){return String(this._wrapped)};var un="[object DataView]";function on(n,r,t,e){if(n===r)return 0!==n||1/n==1/r;if(null==n||null==r)return!1;if(n!=n)return r!=r;var o=typeof n;return("function"===o||"object"===o||"object"==typeof r)&&function n(r,t,e,o){r instanceof tn&&(r=r._wrapped);t instanceof tn&&(t=t._wrapped);var i=a.call(r);if(i!==a.call(t))return!1;if(F&&"[object Object]"==i&&q(r)){if(!q(t))return!1;i=un}switch(i){case"[object RegExp]":case"[object String]":return""+r==""+t;case"[object Number]":return+r!=+r?+t!=+t:0==+r?1/+r==1/t:+r==+t;case"[object Date]":case"[object Boolean]":return+r==+t;case"[object Symbol]":return u.valueOf.call(r)===u.valueOf.call(t);case"[object ArrayBuffer]":case un:return n(en(r),en(t),e,o)}var f="[object Array]"===i;if(!f&&X(r)){if(G(r)!==G(t))return!1;if(r.buffer===t.buffer&&r.byteOffset===t.byteOffset)return!0;f=!0}if(!f){if("object"!=typeof r||"object"!=typeof t)return!1;var c=r.constructor,l=t.constructor;if(c!==l&&!(D(c)&&c instanceof c&&D(l)&&l instanceof l)&&"constructor"in r&&"constructor"in t)return!1}o=o||[];var s=(e=e||[]).length;for(;s--;)if(e[s]===r)return o[s]===t;if(e.push(r),o.push(t),f){if((s=r.length)!==t.length)return!1;for(;s--;)if(!on(r[s],t[s],e,o))return!1}else{var p,v=nn(r);if(s=v.length,nn(t).length!==s)return!1;for(;s--;)if(p=v[s],!W(t,p)||!on(r[p],t[p],e,o))return!1}return e.pop(),o.pop(),!0}(n,r,t,e)}function an(n){if(!_(n))return[];var r=[];for(var t in n)r.push(t);return d&&Z(n,r),r}function fn(n){var r=Y(n);return function(t){if(null==t)return!1;var e=an(t);if(Y(e))return!1;for(var u=0;u<r;u++)if(!D(t[n[u]]))return!1;return n!==hn||!D(t[cn])}}var cn="forEach",ln="has",sn=["clear","delete"],pn=["get",ln,"set"],vn=sn.concat(cn,pn),hn=sn.concat(pn),yn=["add"].concat(sn,cn,ln),gn=V?fn(vn):x("Map"),dn=V?fn(hn):x("WeakMap"),bn=V?fn(yn):x("Set"),mn=x("WeakSet");function jn(n){for(var r=nn(n),t=r.length,e=Array(t),u=0;u<t;u++)e[u]=n[r[u]];return e}function _n(n){for(var r={},t=nn(n),e=0,u=t.length;e<u;e++)r[n[t[e]]]=t[e];return r}function wn(n){var r=[];for(var t in n)D(n[t])&&r.push(t);return r.sort()}function An(n,r){return function(t){var e=arguments.length;if(r&&(t=Object(t)),e<2||null==t)return t;for(var u=1;u<e;u++)for(var o=arguments[u],i=n(o),a=i.length,f=0;f<a;f++){var c=i[f];r&&void 0!==t[c]||(t[c]=o[c])}return t}}var xn=An(an),Sn=An(nn),On=An(an,!0);function Mn(n){if(!_(n))return{};if(v)return v(n);var r=function(){};r.prototype=n;var t=new r;return r.prototype=null,t}function En(n){return _(n)?U(n)?n.slice():xn({},n):n}function Bn(n){return U(n)?n:[n]}function Nn(n){return tn.toPath(n)}function In(n,r){for(var t=r.length,e=0;e<t;e++){if(null==n)return;n=n[r[e]]}return t?n:void 0}function kn(n,r,t){var e=In(n,Nn(r));return w(e)?t:e}function Tn(n){return n}function Dn(n){return n=Sn({},n),function(r){return rn(r,n)}}function Rn(n){return n=Nn(n),function(r){return In(r,n)}}function Fn(n,r,t){if(void 0===r)return n;switch(null==t?3:t){case 1:return function(t){return n.call(r,t)};case 3:return function(t,e,u){return n.call(r,t,e,u)};case 4:return function(t,e,u,o){return n.call(r,t,e,u,o)}}return function(){return n.apply(r,arguments)}}function Vn(n,r,t){return null==n?Tn:D(n)?Fn(n,r,t):_(n)&&!U(n)?Dn(n):Rn(n)}function Pn(n,r){return Vn(n,r,1/0)}function qn(n,r,t){return tn.iteratee!==Pn?tn.iteratee(n,r):Vn(n,r,t)}function Un(){}function Wn(n,r){return null==r&&(r=n,n=0),n+Math.floor(Math.random()*(r-n+1))}tn.toPath=Bn,tn.iteratee=Pn;var zn=Date.now||function(){return(new Date).getTime()};function Ln(n){var r=function(r){return n[r]},t="(?:"+nn(n).join("|")+")",e=RegExp(t),u=RegExp(t,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,r):n}}var Cn={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Kn=Ln(Cn),Jn=Ln(_n(Cn)),$n=tn.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Gn=/(.)^/,Hn={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Qn=/\\|'|\r|\n|\u2028|\u2029/g;function Xn(n){return"\\"+Hn[n]}var Yn=0;function Zn(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var o=Mn(n.prototype),i=n.apply(o,u);return _(i)?i:o}var nr=j((function(n,r){var t=nr.placeholder,e=function(){for(var u=0,o=r.length,i=Array(o),a=0;a<o;a++)i[a]=r[a]===t?arguments[u++]:r[a];for(;u<arguments.length;)i.push(arguments[u++]);return Zn(n,e,this,this,i)};return e}));nr.placeholder=tn;var rr=j((function(n,r,t){if(!D(n))throw new TypeError("Bind must be called on a function");var e=j((function(u){return Zn(n,e,r,this,t.concat(u))}));return e})),tr=J(Y);function er(n,r,t,e){if(e=e||[],r||0===r){if(r<=0)return e.concat(n)}else r=1/0;for(var u=e.length,o=0,i=Y(n);o<i;o++){var a=n[o];if(tr(a)&&(U(a)||L(a)))if(r>1)er(a,r-1,t,e),u=e.length;else for(var f=0,c=a.length;f<c;)e[u++]=a[f++];else t||(e[u++]=a)}return e}var ur=j((function(n,r){var t=(r=er(r,!1,!1)).length;if(t<1)throw new Error("bindAll must be passed function names");for(;t--;){var e=r[t];n[e]=rr(n[e],n)}return n}));var or=j((function(n,r,t){return setTimeout((function(){return n.apply(null,t)}),r)})),ir=nr(or,tn,1);function ar(n){return function(){return!n.apply(this,arguments)}}function fr(n,r){var t;return function(){return--n>0&&(t=r.apply(this,arguments)),n<=1&&(r=null),t}}var cr=nr(fr,2);function lr(n,r,t){r=qn(r,t);for(var e,u=nn(n),o=0,i=u.length;o<i;o++)if(r(n[e=u[o]],e,n))return e}function sr(n){return function(r,t,e){t=qn(t,e);for(var u=Y(r),o=n>0?0:u-1;o>=0&&o<u;o+=n)if(t(r[o],o,r))return o;return-1}}var pr=sr(1),vr=sr(-1);function hr(n,r,t,e){for(var u=(t=qn(t,e,1))(r),o=0,i=Y(n);o<i;){var a=Math.floor((o+i)/2);t(n[a])<u?o=a+1:i=a}return o}function yr(n,r,t){return function(e,u,o){var a=0,f=Y(e);if("number"==typeof o)n>0?a=o>=0?o:Math.max(o+f,a):f=o>=0?Math.min(o+1,f):o+f+1;else if(t&&o&&f)return e[o=t(e,u)]===u?o:-1;if(u!=u)return(o=r(i.call(e,a,f),C))>=0?o+a:-1;for(o=n>0?a:f-1;o>=0&&o<f;o+=n)if(e[o]===u)return o;return-1}}var gr=yr(1,pr,hr),dr=yr(-1,vr);function br(n,r,t){var e=(tr(n)?pr:lr)(n,r,t);if(void 0!==e&&-1!==e)return n[e]}function mr(n,r,t){var e,u;if(r=Fn(r,t),tr(n))for(e=0,u=n.length;e<u;e++)r(n[e],e,n);else{var o=nn(n);for(e=0,u=o.length;e<u;e++)r(n[o[e]],o[e],n)}return n}function jr(n,r,t){r=qn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,o=Array(u),i=0;i<u;i++){var a=e?e[i]:i;o[i]=r(n[a],a,n)}return o}function _r(n){var r=function(r,t,e,u){var o=!tr(r)&&nn(r),i=(o||r).length,a=n>0?0:i-1;for(u||(e=r[o?o[a]:a],a+=n);a>=0&&a<i;a+=n){var f=o?o[a]:a;e=t(e,r[f],f,r)}return e};return function(n,t,e,u){var o=arguments.length>=3;return r(n,Fn(t,u,4),e,o)}}var wr=_r(1),Ar=_r(-1);function xr(n,r,t){var e=[];return r=qn(r,t),mr(n,(function(n,t,u){r(n,t,u)&&e.push(n)})),e}function Sr(n,r,t){r=qn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,o=0;o<u;o++){var i=e?e[o]:o;if(!r(n[i],i,n))return!1}return!0}function Or(n,r,t){r=qn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,o=0;o<u;o++){var i=e?e[o]:o;if(r(n[i],i,n))return!0}return!1}function Mr(n,r,t,e){return tr(n)||(n=jn(n)),("number"!=typeof t||e)&&(t=0),gr(n,r,t)>=0}var Er=j((function(n,r,t){var e,u;return D(r)?u=r:(r=Nn(r),e=r.slice(0,-1),r=r[r.length-1]),jr(n,(function(n){var o=u;if(!o){if(e&&e.length&&(n=In(n,e)),null==n)return;o=n[r]}return null==o?o:o.apply(n,t)}))}));function Br(n,r){return jr(n,Rn(r))}function Nr(n,r,t){var e,u,o=-1/0,i=-1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=tr(n)?n:jn(n)).length;a<f;a++)null!=(e=n[a])&&e>o&&(o=e);else r=qn(r,t),mr(n,(function(n,t,e){((u=r(n,t,e))>i||u===-1/0&&o===-1/0)&&(o=n,i=u)}));return o}function Ir(n,r,t){if(null==r||t)return tr(n)||(n=jn(n)),n[Wn(n.length-1)];var e=tr(n)?En(n):jn(n),u=Y(e);r=Math.max(Math.min(r,u),0);for(var o=u-1,i=0;i<r;i++){var a=Wn(i,o),f=e[i];e[i]=e[a],e[a]=f}return e.slice(0,r)}function kr(n,r){return function(t,e,u){var o=r?[[],[]]:{};return e=qn(e,u),mr(t,(function(r,u){var i=e(r,u,t);n(o,r,i)})),o}}var Tr=kr((function(n,r,t){W(n,t)?n[t].push(r):n[t]=[r]})),Dr=kr((function(n,r,t){n[t]=r})),Rr=kr((function(n,r,t){W(n,t)?n[t]++:n[t]=1})),Fr=kr((function(n,r,t){n[t?0:1].push(r)}),!0),Vr=/[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;function Pr(n,r,t){return r in t}var qr=j((function(n,r){var t={},e=r[0];if(null==n)return t;D(e)?(r.length>1&&(e=Fn(e,r[1])),r=an(n)):(e=Pr,r=er(r,!1,!1),n=Object(n));for(var u=0,o=r.length;u<o;u++){var i=r[u],a=n[i];e(a,i,n)&&(t[i]=a)}return t})),Ur=j((function(n,r){var t,e=r[0];return D(e)?(e=ar(e),r.length>1&&(t=r[1])):(r=jr(er(r,!1,!1),String),e=function(n,t){return!Mr(r,t)}),qr(n,e,t)}));function Wr(n,r,t){return i.call(n,0,Math.max(0,n.length-(null==r||t?1:r)))}function zr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[0]:Wr(n,n.length-r)}function Lr(n,r,t){return i.call(n,null==r||t?1:r)}var Cr=j((function(n,r){return r=er(r,!0,!0),xr(n,(function(n){return!Mr(r,n)}))})),Kr=j((function(n,r){return Cr(n,r)}));function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=qn(t,e));for(var u=[],o=[],i=0,a=Y(n);i<a;i++){var f=n[i],c=t?t(f,i,n):f;r&&!t?(i&&o===c||u.push(f),o=c):t?Mr(o,c)||(o.push(c),u.push(f)):Mr(u,f)||u.push(f)}return u}var $r=j((function(n){return Jr(er(n,!0,!0))}));function Gr(n){for(var r=n&&Nr(n,Y).length||0,t=Array(r),e=0;e<r;e++)t[e]=Br(n,e);return t}var Hr=j(Gr);function Qr(n,r){return n._chain?tn(r).chain():r}function Xr(n){return mr(wn(n),(function(r){var t=tn[r]=n[r];tn.prototype[r]=function(){var n=[this._wrapped];return o.apply(n,arguments),Qr(this,t.apply(tn,n))}})),tn}mr(["pop","push","reverse","shift","sort","splice","unshift"],(function(n){var r=t[n];tn.prototype[n]=function(){var t=this._wrapped;return null!=t&&(r.apply(t,arguments),"shift"!==n&&"splice"!==n||0!==t.length||delete t[0]),Qr(this,t)}})),mr(["concat","join","slice"],(function(n){var r=t[n];tn.prototype[n]=function(){var n=this._wrapped;return null!=n&&(n=r.apply(n,arguments)),Qr(this,n)}}));var Yr=Xr({__proto__:null,VERSION:n,restArguments:j,isObject:_,isNull:function(n){return null===n},isUndefined:w,isBoolean:A,isElement:function(n){return!(!n||1!==n.nodeType)},isString:S,isNumber:O,isDate:M,isRegExp:E,isError:B,isSymbol:N,isArrayBuffer:I,isDataView:q,isArray:U,isFunction:D,isArguments:L,isFinite:function(n){return!N(n)&&g(n)&&!isNaN(parseFloat(n))},isNaN:C,isTypedArray:X,isEmpty:function(n){if(null==n)return!0;var r=Y(n);return"number"==typeof r&&(U(n)||S(n)||L(n))?0===r:0===Y(nn(n))},isMatch:rn,isEqual:function(n,r){return on(n,r)},isMap:gn,isWeakMap:dn,isSet:bn,isWeakSet:mn,keys:nn,allKeys:an,values:jn,pairs:function(n){for(var r=nn(n),t=r.length,e=Array(t),u=0;u<t;u++)e[u]=[r[u],n[r[u]]];return e},invert:_n,functions:wn,methods:wn,extend:xn,extendOwn:Sn,assign:Sn,defaults:On,create:function(n,r){var t=Mn(n);return r&&Sn(t,r),t},clone:En,tap:function(n,r){return r(n),n},get:kn,has:function(n,r){for(var t=(r=Nn(r)).length,e=0;e<t;e++){var u=r[e];if(!W(n,u))return!1;n=n[u]}return!!t},mapObject:function(n,r,t){r=qn(r,t);for(var e=nn(n),u=e.length,o={},i=0;i<u;i++){var a=e[i];o[a]=r(n[a],a,n)}return o},identity:Tn,constant:K,noop:Un,toPath:Bn,property:Rn,propertyOf:function(n){return null==n?Un:function(r){return kn(n,r)}},matcher:Dn,matches:Dn,times:function(n,r,t){var e=Array(Math.max(0,n));r=Fn(r,t,1);for(var u=0;u<n;u++)e[u]=r(u);return e},random:Wn,now:zn,escape:Kn,unescape:Jn,templateSettings:$n,template:function(n,r,t){!r&&t&&(r=t),r=On({},r,tn.templateSettings);var e,u=RegExp([(r.escape||Gn).source,(r.interpolate||Gn).source,(r.evaluate||Gn).source].join("|")+"|$","g"),o=0,i="__p+='";n.replace(u,(function(r,t,e,u,a){return i+=n.slice(o,a).replace(Qn,Xn),o=a+r.length,t?i+="'+\n((__t=("+t+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":u&&(i+="';\n"+u+"\n__p+='"),r})),i+="';\n",r.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{e=new Function(r.variable||"obj","_",i)}catch(n){throw n.source=i,n}var a=function(n){return e.call(this,n,tn)},f=r.variable||"obj";return a.source="function("+f+"){\n"+i+"}",a},result:function(n,r,t){var e=(r=Nn(r)).length;if(!e)return D(t)?t.call(n):t;for(var u=0;u<e;u++){var o=null==n?void 0:n[r[u]];void 0===o&&(o=t,u=e),n=D(o)?o.call(n):o}return n},uniqueId:function(n){var r=++Yn+"";return n?n+r:r},chain:function(n){var r=tn(n);return r._chain=!0,r},iteratee:Pn,partial:nr,bind:rr,bindAll:ur,memoize:function(n,r){var t=function(e){var u=t.cache,o=""+(r?r.apply(this,arguments):e);return W(u,o)||(u[o]=n.apply(this,arguments)),u[o]};return t.cache={},t},delay:or,defer:ir,throttle:function(n,r,t){var e,u,o,i,a=0;t||(t={});var f=function(){a=!1===t.leading?0:zn(),e=null,i=n.apply(u,o),e||(u=o=null)},c=function(){var c=zn();a||!1!==t.leading||(a=c);var l=r-(c-a);return u=this,o=arguments,l<=0||l>r?(e&&(clearTimeout(e),e=null),a=c,i=n.apply(u,o),e||(u=o=null)):e||!1===t.trailing||(e=setTimeout(f,l)),i};return c.cancel=function(){clearTimeout(e),a=0,e=u=o=null},c},debounce:function(n,r,t){var e,u,o=function(r,t){e=null,t&&(u=n.apply(r,t))},i=j((function(i){if(e&&clearTimeout(e),t){var a=!e;e=setTimeout(o,r),a&&(u=n.apply(this,i))}else e=or(o,r,this,i);return u}));return i.cancel=function(){clearTimeout(e),e=null},i},wrap:function(n,r){return nr(r,n)},negate:ar,compose:function(){var n=arguments,r=n.length-1;return function(){for(var t=r,e=n[r].apply(this,arguments);t--;)e=n[t].call(this,e);return e}},after:function(n,r){return function(){if(--n<1)return r.apply(this,arguments)}},before:fr,once:cr,findKey:lr,findIndex:pr,findLastIndex:vr,sortedIndex:hr,indexOf:gr,lastIndexOf:dr,find:br,detect:br,findWhere:function(n,r){return br(n,Dn(r))},each:mr,forEach:mr,map:jr,collect:jr,reduce:wr,foldl:wr,inject:wr,reduceRight:Ar,foldr:Ar,filter:xr,select:xr,reject:function(n,r,t){return xr(n,ar(qn(r)),t)},every:Sr,all:Sr,some:Or,any:Or,contains:Mr,includes:Mr,include:Mr,invoke:Er,pluck:Br,where:function(n,r){return xr(n,Dn(r))},max:Nr,min:function(n,r,t){var e,u,o=1/0,i=1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=tr(n)?n:jn(n)).length;a<f;a++)null!=(e=n[a])&&e<o&&(o=e);else r=qn(r,t),mr(n,(function(n,t,e){((u=r(n,t,e))<i||u===1/0&&o===1/0)&&(o=n,i=u)}));return o},shuffle:function(n){return Ir(n,1/0)},sample:Ir,sortBy:function(n,r,t){var e=0;return r=qn(r,t),Br(jr(n,(function(n,t,u){return{value:n,index:e++,criteria:r(n,t,u)}})).sort((function(n,r){var t=n.criteria,e=r.criteria;if(t!==e){if(t>e||void 0===t)return 1;if(t<e||void 0===e)return-1}return n.index-r.index})),"value")},groupBy:Tr,indexBy:Dr,countBy:Rr,partition:Fr,toArray:function(n){return n?U(n)?i.call(n):S(n)?n.match(Vr):tr(n)?jr(n,Tn):jn(n):[]},size:function(n){return null==n?0:tr(n)?n.length:nn(n).length},pick:qr,omit:Ur,first:zr,head:zr,take:zr,initial:Wr,last:function(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[n.length-1]:Lr(n,Math.max(0,n.length-r))},rest:Lr,tail:Lr,drop:Lr,compact:function(n){return xr(n,Boolean)},flatten:function(n,r){return er(n,r,!1)},without:Kr,uniq:Jr,unique:Jr,union:$r,intersection:function(n){for(var r=[],t=arguments.length,e=0,u=Y(n);e<u;e++){var o=n[e];if(!Mr(r,o)){var i;for(i=1;i<t&&Mr(arguments[i],o);i++);i===t&&r.push(o)}}return r},difference:Cr,unzip:Gr,transpose:Gr,zip:Hr,object:function(n,r){for(var t={},e=0,u=Y(n);e<u;e++)r?t[n[e]]=r[e]:t[n[e][0]]=n[e][1];return t},range:function(n,r,t){null==r&&(r=n||0,n=0),t||(t=r<n?-1:1);for(var e=Math.max(Math.ceil((r-n)/t),0),u=Array(e),o=0;o<e;o++,n+=t)u[o]=n;return u},chunk:function(n,r){if(null==r||r<1)return[];for(var t=[],e=0,u=n.length;e<u;)t.push(i.call(n,e,e+=r));return t},mixin:Xr,default:tn});return Yr._=Yr,Yr}));
\ No newline at end of file diff --git a/sphinx/themes/basic/theme.conf b/sphinx/themes/basic/theme.conf index 3c289d5dc..ff378cab4 100644 --- a/sphinx/themes/basic/theme.conf +++ b/sphinx/themes/basic/theme.conf @@ -12,3 +12,4 @@ body_max_width = 800 navigation_with_keys = False globaltoc_collapse = true globaltoc_includehidden = false +globaltoc_maxdepth = diff --git a/sphinx/themes/bizstyle/layout.html b/sphinx/themes/bizstyle/layout.html index c946f8435..603eb2326 100644 --- a/sphinx/themes/bizstyle/layout.html +++ b/sphinx/themes/bizstyle/layout.html @@ -20,7 +20,7 @@ {%- endblock %} {%- block extrahead %} - <meta name="viewport" content="width=device-width,initial-scale=1.0"> + <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <!--[if lt IE 9]> <script src="_static/css3-mediaqueries.js"></script> <![endif]--> diff --git a/sphinx/themes/bizstyle/static/css3-mediaqueries_src.js b/sphinx/themes/bizstyle/static/css3-mediaqueries_src.js index f21dd4949..787862027 100644 --- a/sphinx/themes/bizstyle/static/css3-mediaqueries_src.js +++ b/sphinx/themes/bizstyle/static/css3-mediaqueries_src.js @@ -1035,7 +1035,7 @@ domReady(function enableCssMediaQueries() { var vpw = cssHelper.getViewportWidth(); var vph = cssHelper.getViewportHeight(); // check whether vp size has really changed, because IE also triggers resize event when body size changes - // 20px allowance to accomodate short appearance of scrollbars in IE in some cases + // 20px allowance to accommodate short appearance of scrollbars in IE in some cases if (Math.abs(vpw - cvpw) > scrollbarWidth || Math.abs(vph - cvph) > scrollbarWidth) { cvpw = vpw; cvph = vph; diff --git a/sphinx/themes/classic/layout.html b/sphinx/themes/classic/layout.html index c638c7f90..dbb30b98c 100644 --- a/sphinx/themes/classic/layout.html +++ b/sphinx/themes/classic/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the classic theme. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/classic/static/classic.css_t b/sphinx/themes/classic/static/classic.css_t index bdd9db75f..4a31edf6a 100644 --- a/sphinx/themes/classic/static/classic.css_t +++ b/sphinx/themes/classic/static/classic.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- classic theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/classic/static/sidebar.js_t b/sphinx/themes/classic/static/sidebar.js_t index 46437dae5..e1d323b24 100644 --- a/sphinx/themes/classic/static/sidebar.js_t +++ b/sphinx/themes/classic/static/sidebar.js_t @@ -16,7 +16,7 @@ * Once the browser is closed the cookie is deleted and the position * reset to the default (expanded). * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/classic/theme.conf b/sphinx/themes/classic/theme.conf index d7389eaa0..cd16f4b47 100644 --- a/sphinx/themes/classic/theme.conf +++ b/sphinx/themes/classic/theme.conf @@ -25,8 +25,8 @@ headtextcolor = #20435c headlinkcolor = #c60f0f linkcolor = #355f7c visitedlinkcolor = #355f7c -codebgcolor = #eeffcc -codetextcolor = #333333 +codebgcolor = unset +codetextcolor = unset bodyfont = sans-serif headfont = 'Trebuchet MS', sans-serif diff --git a/sphinx/themes/epub/epub-cover.html b/sphinx/themes/epub/epub-cover.html index 49a7de3a3..70a5a556b 100644 --- a/sphinx/themes/epub/epub-cover.html +++ b/sphinx/themes/epub/epub-cover.html @@ -4,7 +4,7 @@ Sample template for the html cover page. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/epub/layout.html b/sphinx/themes/epub/layout.html index 03f03e267..4f52fc891 100644 --- a/sphinx/themes/epub/layout.html +++ b/sphinx/themes/epub/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the epub theme. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/epub/static/epub.css_t b/sphinx/themes/epub/static/epub.css_t index 1e81c182c..46bbb93b3 100644 --- a/sphinx/themes/epub/static/epub.css_t +++ b/sphinx/themes/epub/static/epub.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- epub theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/haiku/layout.html b/sphinx/themes/haiku/layout.html index c47b8eccc..2c2469722 100644 --- a/sphinx/themes/haiku/layout.html +++ b/sphinx/themes/haiku/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the haiku theme. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/haiku/static/haiku.css_t b/sphinx/themes/haiku/static/haiku.css_t index cac283400..fa9f77b9d 100644 --- a/sphinx/themes/haiku/static/haiku.css_t +++ b/sphinx/themes/haiku/static/haiku.css_t @@ -16,7 +16,7 @@ * Braden Ewing <brewin@gmail.com> * Humdinger <humdingerb@gmail.com> * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -319,7 +319,6 @@ pre { border-width: thin; margin: 0 0 12px 0; padding: 0.8em; - background-color: #f0f0f0; } hr { diff --git a/sphinx/themes/nature/static/nature.css_t b/sphinx/themes/nature/static/nature.css_t index 13c64467b..3dd748dda 100644 --- a/sphinx/themes/nature/static/nature.css_t +++ b/sphinx/themes/nature/static/nature.css_t @@ -4,15 +4,15 @@ * * Sphinx stylesheet -- nature theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ - + @import url("basic.css"); - + /* -- page layout ----------------------------------------------------------- */ - + body { font-family: Arial, sans-serif; font-size: 100%; @@ -34,18 +34,18 @@ div.bodywrapper { hr { border: 1px solid #B1B4B6; } - + div.document { background-color: #eee; } - + div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; font-size: 0.9em; } - + div.footer { color: #555; width: 100%; @@ -53,12 +53,12 @@ div.footer { text-align: center; font-size: 75%; } - + div.footer a { color: #444; text-decoration: underline; } - + div.related { background-color: #6BA81E; line-height: 32px; @@ -66,11 +66,11 @@ div.related { text-shadow: 0px 1px 0 #444; font-size: 0.9em; } - + div.related a { color: #E2F3CC; } - + div.sphinxsidebar { font-size: 0.75em; line-height: 1.5em; @@ -79,7 +79,7 @@ div.sphinxsidebar { div.sphinxsidebarwrapper{ padding: 20px 0; } - + div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: Arial, sans-serif; @@ -95,30 +95,30 @@ div.sphinxsidebar h4 { div.sphinxsidebar h4{ font-size: 1.1em; } - + div.sphinxsidebar h3 a { color: #444; } - - + + div.sphinxsidebar p { color: #888; padding: 5px 20px; } - + div.sphinxsidebar p.topless { } - + div.sphinxsidebar ul { margin: 10px 20px; padding: 0; color: #000; } - + div.sphinxsidebar a { color: #444; } - + div.sphinxsidebar input { border: 1px solid #ccc; font-family: sans-serif; @@ -131,17 +131,17 @@ div.sphinxsidebar .searchformwrapper { } /* -- body styles ----------------------------------------------------------- */ - + a { color: #005B81; text-decoration: none; } - + a:hover { color: #E32E00; text-decoration: underline; } - + div.body h1, div.body h2, div.body h3, @@ -156,69 +156,63 @@ div.body h6 { padding: 5px 0 5px 10px; text-shadow: 0px 1px 0 white } - + div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } div.body h2 { font-size: 150%; background-color: #C8D5E3; } div.body h3 { font-size: 120%; background-color: #D8DEE3; } div.body h4 { font-size: 110%; background-color: #D8DEE3; } div.body h5 { font-size: 100%; background-color: #D8DEE3; } div.body h6 { font-size: 100%; background-color: #D8DEE3; } - + a.headerlink { color: #c60f0f; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } - + a.headerlink:hover { background-color: #c60f0f; color: white; } - + div.body p, div.body dd, div.body li { line-height: 1.5em; } - + div.admonition p.admonition-title + p { display: inline; } -div.highlight{ - background-color: white; -} - div.note { background-color: #eee; border: 1px solid #ccc; } - + div.seealso { background-color: #ffc; border: 1px solid #ff6; } - + div.topic { background-color: #eee; } - + div.warning { background-color: #ffe4e4; border: 1px solid #f66; } - + p.admonition-title { display: inline; } - + p.admonition-title:after { content: ":"; } - + pre { padding: 10px; - background-color: White; - color: #222; line-height: 1.2em; border: 1px solid #C6C9CB; font-size: 1.1em; @@ -226,7 +220,7 @@ pre { -webkit-box-shadow: 1px 1px 1px #d8d8d8; -moz-box-shadow: 1px 1px 1px #d8d8d8; } - + code { background-color: #ecf0f3; color: #222; diff --git a/sphinx/themes/nonav/layout.html b/sphinx/themes/nonav/layout.html index 256b9a228..d39800c18 100644 --- a/sphinx/themes/nonav/layout.html +++ b/sphinx/themes/nonav/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the any help system theme. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/nonav/static/nonav.css b/sphinx/themes/nonav/static/nonav.css index d37c76221..63abb9f0d 100644 --- a/sphinx/themes/nonav/static/nonav.css +++ b/sphinx/themes/nonav/static/nonav.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- nonav theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/pyramid/static/epub.css b/sphinx/themes/pyramid/static/epub.css index 270e9570e..6e5722fd6 100644 --- a/sphinx/themes/pyramid/static/epub.css +++ b/sphinx/themes/pyramid/static/epub.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- default theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/pyramid/static/pyramid.css_t b/sphinx/themes/pyramid/static/pyramid.css_t index 48cb2ab6f..9857f2850 100644 --- a/sphinx/themes/pyramid/static/pyramid.css_t +++ b/sphinx/themes/pyramid/static/pyramid.css_t @@ -4,15 +4,15 @@ * * Sphinx stylesheet -- pylons theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ - + @import url("basic.css"); - + /* -- page layout ----------------------------------------------------------- */ - + body { font-family: "Nobile", sans-serif; font-size: 100%; @@ -34,7 +34,7 @@ div.bodywrapper { hr { border: 1px solid #B1B4B6; } - + div.document { background-color: #eee; } @@ -59,7 +59,7 @@ div.body { border-right-style: none; overflow: auto; } - + div.footer { color: #ffffff; width: 100%; @@ -69,7 +69,7 @@ div.footer { background: transparent; clear:both; } - + div.footer a { color: #ffffff; text-decoration: none; @@ -79,14 +79,14 @@ div.footer a:hover { color: #e88f00; text-decoration: underline; } - + div.related { line-height: 30px; color: #373839; font-size: 0.8em; background-color: #eee; } - + div.related a { color: #1b61d6; } @@ -94,7 +94,7 @@ div.related a { div.related ul { padding-left: calc({{ theme_sidebarwidth|todim }} + 10px); } - + div.sphinxsidebar { font-size: 0.75em; line-height: 1.5em; @@ -103,7 +103,7 @@ div.sphinxsidebar { div.sphinxsidebarwrapper{ padding: 10px 0; } - + div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: "Neuton", sans-serif; @@ -118,30 +118,30 @@ div.sphinxsidebar h4 { div.sphinxsidebar h4{ font-size: 1.3em; } - + div.sphinxsidebar h3 a { color: #000000; } - - + + div.sphinxsidebar p { color: #888; padding: 5px 20px; } - + div.sphinxsidebar p.topless { } - + div.sphinxsidebar ul { margin: 10px 20px; padding: 0; color: #373839; } - + div.sphinxsidebar a { color: #444; } - + div.sphinxsidebar input { border: 1px solid #ccc; font-family: sans-serif; @@ -171,16 +171,16 @@ p.sidebar-title { } /* -- body styles ----------------------------------------------------------- */ - + a, a .pre { color: #1b61d6; text-decoration: none; } - + a:hover, a:hover .pre { text-decoration: underline; } - + div.body h1, div.body h2, div.body h3, @@ -194,29 +194,29 @@ div.body h6 { margin: 30px 0px 10px 0px; padding: 5px 0; } - + div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } div.body h2 { font-size: 150%; background-color: #ffffff; } div.body h3 { font-size: 120%; background-color: #ffffff; } div.body h4 { font-size: 110%; background-color: #ffffff; } div.body h5 { font-size: 100%; background-color: #ffffff; } div.body h6 { font-size: 100%; background-color: #ffffff; } - + a.headerlink { color: #1b61d6; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } - + a.headerlink:hover { text-decoration: underline; } - + div.body p, div.body dd, div.body li { line-height: 1.5em; } - + div.admonition p.admonition-title + p { display: inline; } @@ -229,10 +229,6 @@ div.admonition { padding: 10px 20px 10px 60px; } -div.highlight{ - background-color: white; -} - div.note { border: 2px solid #7a9eec; border-right-style: none; @@ -240,7 +236,7 @@ div.note { padding: 10px 20px 10px 60px; background: #e1ecfe url(dialog-note.png) no-repeat 10px 8px; } - + div.seealso { background: #fff6bf url(dialog-seealso.png) no-repeat 10px 8px; border: 2px solid #ffd324; @@ -248,7 +244,7 @@ div.seealso { border-right-style: none; padding: 10px 20px 10px 60px; } - + div.topic { background: #eeeeee; border: 2px solid #C6C9CB; @@ -256,7 +252,7 @@ div.topic { border-right-style: none; border-left-style: none; } - + div.warning { background: #fbe3e4 url(dialog-warning.png) no-repeat 10px 8px; border: 2px solid #fbc2c4; @@ -272,22 +268,20 @@ div.admonition-todo { border-left-style: none; padding: 10px 20px 10px 60px; } - + div.note p.admonition-title, div.warning p.admonition-title, div.seealso p.admonition-title, div.admonition-todo p.admonition-title { display: none; } - + p.admonition-title:after { content: ":"; } - + pre { padding: 10px; - background-color: #fafafa; - color: #222; line-height: 1.2em; border: 2px solid #C6C9CB; font-size: 1.1em; @@ -295,7 +289,7 @@ pre { border-right-style: none; border-left-style: none; } - + code { background-color: transparent; color: #222; diff --git a/sphinx/themes/scrolls/layout.html b/sphinx/themes/scrolls/layout.html index 7866a5162..066d9f668 100644 --- a/sphinx/themes/scrolls/layout.html +++ b/sphinx/themes/scrolls/layout.html @@ -5,7 +5,7 @@ Sphinx layout template for the scrolls theme, originally written by Armin Ronacher. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/scrolls/static/scrolls.css_t b/sphinx/themes/scrolls/static/scrolls.css_t index b01d4ad9f..f039d9e2b 100644 --- a/sphinx/themes/scrolls/static/scrolls.css_t +++ b/sphinx/themes/scrolls/static/scrolls.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- scrolls theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -188,7 +188,7 @@ a:hover { } pre { - background: #ededed url(metal.png); + background-image: url(metal.png); border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; padding: 5px; diff --git a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t index 626d8c3f2..4be04ce71 100644 --- a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +++ b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t @@ -5,7 +5,7 @@ * Sphinx stylesheet -- sphinxdoc theme. Originally created by * Armin Ronacher for Werkzeug. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -138,7 +138,7 @@ div.footer a { /* -- body styles ----------------------------------------------------------- */ -p { +p { margin: 0.8em 0 0.5em 0; } @@ -247,7 +247,6 @@ pre { line-height: 120%; padding: 0.5em; border: 1px solid #ccc; - background-color: #f8f8f8; } pre a { diff --git a/sphinx/themes/traditional/static/traditional.css_t b/sphinx/themes/traditional/static/traditional.css_t index 68719dcd1..4371d8e89 100644 --- a/sphinx/themes/traditional/static/traditional.css_t +++ b/sphinx/themes/traditional/static/traditional.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- traditional docs.python.org theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -632,7 +632,6 @@ th { pre { font-family: monospace; padding: 5px; - color: #00008b; border-left: none; border-right: none; } diff --git a/sphinx/theming.py b/sphinx/theming.py index 13a895393..30e4dffdb 100644 --- a/sphinx/theming.py +++ b/sphinx/theming.py @@ -4,7 +4,7 @@ Theming support for HTML builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -74,17 +74,17 @@ class Theme: try: inherit = self.config.get('theme', 'inherit') - except configparser.NoSectionError: - raise ThemeError(__('theme %r doesn\'t have "theme" setting') % name) - except configparser.NoOptionError: - raise ThemeError(__('theme %r doesn\'t have "inherit" setting') % name) + except configparser.NoSectionError as exc: + raise ThemeError(__('theme %r doesn\'t have "theme" setting') % name) from exc + except configparser.NoOptionError as exc: + raise ThemeError(__('theme %r doesn\'t have "inherit" setting') % name) from exc if inherit != 'none': try: self.base = factory.create(inherit) - except ThemeError: + except ThemeError as exc: raise ThemeError(__('no theme named %r found, inherited by %r') % - (inherit, name)) + (inherit, name)) from exc def get_theme_dirs(self) -> List[str]: """Return a list of theme directories, beginning with this theme's, @@ -101,13 +101,13 @@ class Theme: """ try: return self.config.get(section, name) - except (configparser.NoOptionError, configparser.NoSectionError): + except (configparser.NoOptionError, configparser.NoSectionError) as exc: if self.base: return self.base.get_config(section, name, default) if default is NODEFAULT: raise ThemeError(__('setting %s.%s occurs in none of the ' - 'searched theme configs') % (section, name)) + 'searched theme configs') % (section, name)) from exc else: return default diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index 1605c95b9..45640308f 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -4,7 +4,7 @@ Docutils transforms used by Sphinx when reading documents. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -23,8 +23,7 @@ from sphinx import addnodes from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.locale import _, __ -from sphinx.util import docutils -from sphinx.util import logging +from sphinx.util import docutils, logging from sphinx.util.docutils import new_document from sphinx.util.i18n import format_date from sphinx.util.nodes import NodeMatcher, apply_source_workaround, is_smartquotable @@ -401,16 +400,21 @@ class ManpageLink(SphinxTransform): node.attributes.update(info) -from sphinx.domains.citation import ( # NOQA - CitationDefinitionTransform, CitationReferenceTransform -) +from sphinx.domains.citation import CitationDefinitionTransform # NOQA +from sphinx.domains.citation import CitationReferenceTransform # NOQA deprecated_alias('sphinx.transforms', { 'CitationReferences': CitationReferenceTransform, 'SmartQuotesSkipper': CitationDefinitionTransform, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'CitationReferences': + 'sphinx.domains.citation.CitationReferenceTransform', + 'SmartQuotesSkipper': + 'sphinx.domains.citation.CitationDefinitionTransform', + }) def setup(app: "Sphinx") -> Dict[str, Any]: diff --git a/sphinx/transforms/compact_bullet_list.py b/sphinx/transforms/compact_bullet_list.py index 1cde3b1f0..18042358e 100644 --- a/sphinx/transforms/compact_bullet_list.py +++ b/sphinx/transforms/compact_bullet_list.py @@ -4,12 +4,11 @@ Docutils transforms used by Sphinx when reading documents. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, List -from typing import cast +from typing import Any, Dict, List, cast from docutils import nodes from docutils.nodes import Node diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index 34d5b1368..8520cfc69 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -4,7 +4,7 @@ Docutils transforms used by Sphinx when reading documents. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -20,23 +20,30 @@ from docutils.utils import relative_path from sphinx import addnodes from sphinx.config import Config from sphinx.domains.std import make_glossary_term, split_term_classifiers -from sphinx.locale import __, init as init_locale +from sphinx.locale import __ +from sphinx.locale import init as init_locale from sphinx.transforms import SphinxTransform -from sphinx.util import split_index_msg, logging, get_filetype +from sphinx.util import get_filetype, logging, split_index_msg from sphinx.util.i18n import docname_to_domain -from sphinx.util.nodes import ( - LITERAL_TYPE_NODES, IMAGE_TYPE_NODES, NodeMatcher, - extract_messages, is_pending_meta, traverse_translatable_index, -) +from sphinx.util.nodes import (IMAGE_TYPE_NODES, LITERAL_TYPE_NODES, NodeMatcher, + extract_messages, is_pending_meta, traverse_translatable_index) if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx logger = logging.getLogger(__name__) +# The attributes not copied to the translated node +# +# * refexplict: For allow to give (or not to give) an explicit title +# to the pending_xref on translation +EXCLUDED_PENDING_XREF_ATTRIBUTES = ('refexplicit',) + + N = TypeVar('N', bound=nodes.Node) @@ -426,11 +433,8 @@ class Locale(SphinxTransform): # Copy attributes to keep original node behavior. Especially # copying 'reftarget', 'py:module', 'py:class' are needed. for k, v in xref_reftarget_map.get(key, {}).items(): - # Note: This implementation overwrite all attributes. - # if some attributes `k` should not be overwritten, - # you should provide exclude list as: - # `if k not in EXCLUDE_LIST: new[k] = v` - new[k] = v + if k not in EXCLUDED_PENDING_XREF_ATTRIBUTES: + new[k] = v # update leaves for child in patch.children: diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 4499e3376..1c424050a 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -4,12 +4,11 @@ Docutils transforms used by Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from typing import Any, Dict, List, Tuple, Type -from typing import cast +from typing import Any, Dict, List, Optional, Tuple, Type, cast from docutils import nodes from docutils.nodes import Element @@ -25,7 +24,6 @@ from sphinx.util import logging from sphinx.util.docutils import SphinxTranslator from sphinx.util.nodes import process_only_nodes - logger = logging.getLogger(__name__) @@ -82,8 +80,8 @@ class ReferencesResolver(SphinxPostTransform): # let the domain try to resolve the reference try: domain = self.env.domains[node['refdomain']] - except KeyError: - raise NoUri(target, typ) + except KeyError as exc: + raise NoUri(target, typ) from exc newnode = domain.resolve_xref(self.env, refdoc, self.app.builder, typ, target, node, contnode) # really hardwired reference types @@ -152,7 +150,7 @@ class ReferencesResolver(SphinxPostTransform): return newnode def warn_missing_reference(self, refdoc: str, typ: str, target: str, - node: pending_xref, domain: Domain) -> None: + node: pending_xref, domain: Optional[Domain]) -> None: warn = node.get('refwarn') if self.config.nitpicky: warn = True @@ -166,7 +164,10 @@ class ReferencesResolver(SphinxPostTransform): warn = False if not warn: return - if domain and typ in domain.dangling_warnings: + + if self.app.emit_firstresult('warn-missing-reference', domain, node): + return + elif domain and typ in domain.dangling_warnings: msg = domain.dangling_warnings[typ] elif node.get('refdomain', 'std') not in ('', 'std'): msg = (__('%s:%s reference target not found: %%(target)s') % diff --git a/sphinx/transforms/post_transforms/code.py b/sphinx/transforms/post_transforms/code.py index add35647b..20df1db3c 100644 --- a/sphinx/transforms/post_transforms/code.py +++ b/sphinx/transforms/post_transforms/code.py @@ -4,15 +4,15 @@ transforms for code-blocks. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import sys -from typing import Any, Dict, List, NamedTuple, Union +from typing import Any, Dict, List, NamedTuple from docutils import nodes -from docutils.nodes import Node +from docutils.nodes import Node, TextElement from pygments.lexers import PythonConsoleLexer, guess_lexer from sphinx import addnodes @@ -20,7 +20,6 @@ from sphinx.application import Sphinx from sphinx.ext import doctest from sphinx.transforms import SphinxTransform - HighlightSetting = NamedTuple('HighlightSetting', [('language', str), ('force', bool), ('lineno_threshold', int)]) @@ -93,9 +92,6 @@ class TrimDoctestFlagsTransform(SphinxTransform): default_priority = HighlightLanguageTransform.default_priority + 1 def apply(self, **kwargs: Any) -> None: - if not self.config.trim_doctest_flags: - return - for lbnode in self.document.traverse(nodes.literal_block): # type: nodes.literal_block if self.is_pyconsole(lbnode): self.strip_doctest_flags(lbnode) @@ -103,8 +99,10 @@ class TrimDoctestFlagsTransform(SphinxTransform): for dbnode in self.document.traverse(nodes.doctest_block): # type: nodes.doctest_block self.strip_doctest_flags(dbnode) - @staticmethod - def strip_doctest_flags(node: Union[nodes.literal_block, nodes.doctest_block]) -> None: + def strip_doctest_flags(self, node: TextElement) -> None: + if not node.get('trim_flags', self.config.trim_doctest_flags): + return + source = node.rawsource source = doctest.blankline_re.sub('', source) source = doctest.doctestopt_re.sub('', source) diff --git a/sphinx/transforms/post_transforms/images.py b/sphinx/transforms/post_transforms/images.py index f2cacac3c..2603e0458 100644 --- a/sphinx/transforms/post_transforms/images.py +++ b/sphinx/transforms/post_transforms/images.py @@ -4,25 +4,23 @@ Docutils transforms used by Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import re from math import ceil -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Optional, Tuple from docutils import nodes from sphinx.application import Sphinx from sphinx.locale import __ from sphinx.transforms import SphinxTransform -from sphinx.util import epoch_to_rfc1123, rfc1123_to_epoch, sha1 -from sphinx.util import logging, requests -from sphinx.util.images import guess_mimetype, get_image_extension, parse_data_uri -from sphinx.util.osutil import ensuredir, movefile - +from sphinx.util import epoch_to_rfc1123, logging, requests, rfc1123_to_epoch, sha1 +from sphinx.util.images import get_image_extension, guess_mimetype, parse_data_uri +from sphinx.util.osutil import ensuredir logger = logging.getLogger(__name__) @@ -101,7 +99,7 @@ class ImageDownloader(BaseImageConverter): # append a suffix if URI does not contain suffix ext = get_image_extension(mimetype) newpath = os.path.join(self.imagedir, dirname, basename + ext) - movefile(path, newpath) + os.replace(path, newpath) self.app.env.original_image_uri.pop(path) self.app.env.original_image_uri[newpath] = node['uri'] path = newpath @@ -175,6 +173,13 @@ class ImageConverter(BaseImageConverter): """ default_priority = 200 + #: The converter is available or not. Will be filled at the first call of + #: the build. The result is shared in the same process. + #: + #: .. todo:: This should be refactored not to store the state without class + #: variable. + available = None # type: Optional[bool] + #: A conversion rules the image converter supports. #: It is represented as a list of pair of source image format (mimetype) and #: destination one:: @@ -187,22 +192,20 @@ class ImageConverter(BaseImageConverter): conversion_rules = [] # type: List[Tuple[str, str]] def __init__(self, *args: Any, **kwargs: Any) -> None: - self.available = None # type: bool - # the converter is available or not. - # Will be checked at first conversion super().__init__(*args, **kwargs) def match(self, node: nodes.image) -> bool: if not self.app.builder.supported_image_types: return False + elif set(node['candidates']) & set(self.app.builder.supported_image_types): + # builder supports the image; no need to convert + return False elif self.available is None: - self.available = self.is_available() + # store the value to the class variable to share it during the build + self.__class__.available = self.is_available() if not self.available: return False - elif set(node['candidates']) & set(self.app.builder.supported_image_types): - # builder supports the image; no need to convert - return False else: rule = self.get_conversion_rule(node) if rule: diff --git a/sphinx/transforms/references.py b/sphinx/transforms/references.py index e74d9657d..cd564d9eb 100644 --- a/sphinx/transforms/references.py +++ b/sphinx/transforms/references.py @@ -4,14 +4,13 @@ Docutils transforms used by Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from typing import Any, Dict -from docutils import nodes -from docutils.transforms.references import DanglingReferences, Substitutions +from docutils.transforms.references import DanglingReferences from sphinx.transforms import SphinxTransform @@ -20,17 +19,6 @@ if False: from sphinx.application import Sphinx -class SubstitutionDefinitionsRemover(SphinxTransform): - """Remove ``substitution_definition node from doctrees.""" - - # should be invoked after Substitutions process - default_priority = Substitutions.default_priority + 1 - - def apply(self, **kwargs: Any) -> None: - for node in self.document.traverse(nodes.substitution_definition): - node.parent.remove(node) - - class SphinxDanglingReferences(DanglingReferences): """DanglingReferences transform which does not output info messages.""" @@ -56,7 +44,6 @@ class SphinxDomains(SphinxTransform): def setup(app: "Sphinx") -> Dict[str, Any]: - app.add_transform(SubstitutionDefinitionsRemover) app.add_transform(SphinxDanglingReferences) app.add_transform(SphinxDomains) diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index ca9bb028d..2fbc182e5 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -4,7 +4,7 @@ Utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -25,33 +25,29 @@ from datetime import datetime from importlib import import_module from os import path from time import mktime, strptime -from typing import Any, Callable, Dict, IO, Iterable, Iterator, List, Pattern, Set, Tuple -from urllib.parse import urlsplit, urlunsplit, quote_plus, parse_qsl, urlencode +from typing import IO, Any, Callable, Dict, Iterable, Iterator, List, Pattern, Set, Tuple +from urllib.parse import parse_qsl, quote_plus, urlencode, urlsplit, urlunsplit from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning -from sphinx.errors import ( - PycodeError, SphinxParallelError, ExtensionError, FiletypeNotFoundError -) +from sphinx.errors import (ExtensionError, FiletypeNotFoundError, PycodeError, + SphinxParallelError) from sphinx.locale import __ -from sphinx.util import logging -from sphinx.util.console import strip_colors, colorize, bold, term_width_line # type: ignore -from sphinx.util.typing import PathMatcher from sphinx.util import smartypants # noqa - +from sphinx.util import logging +from sphinx.util.console import bold, colorize, strip_colors, term_width_line # type: ignore +from sphinx.util.matching import patfilter # noqa +from sphinx.util.nodes import (caption_ref_re, explicit_title_re, # noqa + nested_parse_with_titles, split_explicit_title) # import other utilities; partly for backwards compatibility, so don't # prune unused ones indiscriminately -from sphinx.util.osutil import ( # noqa - SEP, os_path, relative_uri, ensuredir, walk, mtimes_of_files, movefile, - copyfile, copytimes, make_filename) -from sphinx.util.nodes import ( # noqa - nested_parse_with_titles, split_explicit_title, explicit_title_re, - caption_ref_re) -from sphinx.util.matching import patfilter # noqa - +from sphinx.util.osutil import (SEP, copyfile, copytimes, ensuredir, make_filename, # noqa + movefile, mtimes_of_files, os_path, relative_uri, walk) +from sphinx.util.typing import PathMatcher if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx @@ -241,10 +237,12 @@ _DEBUG_HEADER = '''\ def save_traceback(app: "Sphinx") -> str: """Save the current exception's traceback in a temporary file.""" - import sphinx - import jinja2 - import docutils import platform + + import docutils + import jinja2 + + import sphinx exc = sys.exc_info()[1] if isinstance(exc, SphinxParallelError): exc_format = '(Error in parallel process)\n' + exc.traceback @@ -285,21 +283,21 @@ def get_module_source(modname: str) -> Tuple[str, str]: try: mod = import_module(modname) except Exception as err: - raise PycodeError('error importing %r' % modname, err) + raise PycodeError('error importing %r' % modname, err) from err filename = getattr(mod, '__file__', None) loader = getattr(mod, '__loader__', None) if loader and getattr(loader, 'get_filename', None): try: filename = loader.get_filename(modname) except Exception as err: - raise PycodeError('error getting filename for %r' % filename, err) + raise PycodeError('error getting filename for %r' % filename, err) from err if filename is None and loader: try: filename = loader.get_source(modname) if filename: return 'string', filename except Exception as err: - raise PycodeError('error getting source for %r' % modname, err) + raise PycodeError('error getting source for %r' % modname, err) from err if filename is None: raise PycodeError('no source found for module %r' % modname) filename = path.normpath(path.abspath(filename)) @@ -328,7 +326,7 @@ def get_full_modname(modname: str, attribute: str) -> str: return None module = import_module(modname) - # Allow an attribute to have multiple parts and incidentially allow + # Allow an attribute to have multiple parts and incidentally allow # repeated .s in the attribute. value = module for attr in attribute.split('.'): @@ -456,8 +454,8 @@ def parselinenos(spec: str, total: int) -> List[int]: items.extend(range(start - 1, end)) else: raise ValueError - except Exception: - raise ValueError('invalid line number spec: %r' % spec) + except Exception as exc: + raise ValueError('invalid line number spec: %r' % spec) from exc return items @@ -596,9 +594,9 @@ def import_object(objname: str, source: str = None) -> Any: except (AttributeError, ImportError) as exc: if source: raise ExtensionError('Could not import %s (needed for %s)' % - (objname, source), exc) + (objname, source), exc) from exc else: - raise ExtensionError('Could not import %s' % objname, exc) + raise ExtensionError('Could not import %s' % objname, exc) from exc def split_full_qualified_name(name: str) -> Tuple[str, str]: @@ -621,7 +619,12 @@ def split_full_qualified_name(name: str) -> Tuple[str, str]: modname = ".".join(parts[:i]) import_module(modname) except ImportError: - return ".".join(parts[:i - 1]), ".".join(parts[i - 1:]) + if parts[:i - 1]: + return ".".join(parts[:i - 1]), ".".join(parts[i - 1:]) + else: + return None, ".".join(parts) + except IndexError: + pass return name, "" diff --git a/sphinx/util/build_phase.py b/sphinx/util/build_phase.py index d6193b400..07a5ee7cd 100644 --- a/sphinx/util/build_phase.py +++ b/sphinx/util/build_phase.py @@ -4,7 +4,7 @@ Build phase of Sphinx application. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py index edccf96a7..1549fbf75 100644 --- a/sphinx/util/cfamily.py +++ b/sphinx/util/cfamily.py @@ -4,16 +4,14 @@ Utility functions common to the C and C++ domains. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re import warnings from copy import deepcopy -from typing import ( - Any, Callable, List, Match, Pattern, Tuple, Union -) +from typing import Any, Callable, List, Match, Optional, Pattern, Tuple, Union from docutils import nodes from docutils.nodes import TextElement @@ -110,7 +108,6 @@ class ASTBaseBase: __hash__ = None # type: Callable[[], int] def clone(self) -> Any: - """Clone a definition expression node.""" return deepcopy(self) def _stringify(self, transform: StringifyTransform) -> str: @@ -148,16 +145,14 @@ class ASTCPPAttribute(ASTAttribute): class ASTGnuAttribute(ASTBaseBase): - def __init__(self, name: str, args: Any) -> None: + def __init__(self, name: str, args: Optional["ASTBaseParenExprList"]) -> None: self.name = name self.args = args def _stringify(self, transform: StringifyTransform) -> str: res = [self.name] if self.args: - res.append('(') res.append(transform(self.args)) - res.append(')') return ''.join(res) @@ -211,6 +206,11 @@ class ASTParenAttribute(ASTAttribute): ################################################################################ +class ASTBaseParenExprList(ASTBaseBase): + pass + + +################################################################################ class UnsupportedMultiCharacterCharLiteral(Exception): @property @@ -389,7 +389,7 @@ class BaseParser: % startPos) return self.definition[startPos:self.pos] - def _parse_attribute(self) -> ASTAttribute: + def _parse_attribute(self) -> Optional[ASTAttribute]: self.skip_ws() # try C++11 style startPos = self.pos @@ -415,11 +415,8 @@ class BaseParser: while 1: if self.match(identifier_re): name = self.matched_text - self.skip_ws() - if self.skip_string_and_ws('('): - self.fail('Parameterized GNU style attribute not yet supported.') - attrs.append(ASTGnuAttribute(name, None)) - # TODO: parse arguments for the attribute + exprs = self._parse_paren_expression_list() + attrs.append(ASTGnuAttribute(name, exprs)) if self.skip_string_and_ws(','): continue elif self.skip_string_and_ws(')'): @@ -447,3 +444,6 @@ class BaseParser: return ASTParenAttribute(id, arg) return None + + def _parse_paren_expression_list(self) -> ASTBaseParenExprList: + raise NotImplementedError diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py index 4923343ae..dbe902be7 100644 --- a/sphinx/util/compat.py +++ b/sphinx/util/compat.py @@ -4,7 +4,7 @@ modules for backward compatibility - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -27,7 +27,7 @@ def register_application_for_autosummary(app: "Sphinx") -> None: """Register application object to autosummary module. Since Sphinx-1.7, documenters and attrgetters are registered into - applicaiton object. As a result, the arguments of + application object. As a result, the arguments of ``get_documenter()`` has been changed. To keep compatibility, this handler registers application object to the module. """ diff --git a/sphinx/util/console.py b/sphinx/util/console.py index 98563f58e..3ea5b9573 100644 --- a/sphinx/util/console.py +++ b/sphinx/util/console.py @@ -4,7 +4,7 @@ Format colored console output. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -32,11 +32,10 @@ def terminal_safe(s: str) -> str: def get_terminal_width() -> int: """Borrowed from the py lib.""" try: - import termios import fcntl import struct - call = fcntl.ioctl(0, termios.TIOCGWINSZ, # type: ignore - struct.pack('hhhh', 0, 0, 0, 0)) + import termios + call = fcntl.ioctl(0, termios.TIOCGWINSZ, struct.pack('hhhh', 0, 0, 0, 0)) height, width = struct.unpack('hhhh', call)[:2] terminal_width = width except Exception: diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index c07bc7f66..3fc72340a 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -5,13 +5,12 @@ "Doc fields" are reST field lists in object descriptions that will be domain-specifically transformed to a more appealing presentation. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import warnings -from typing import Any, Dict, List, Tuple, Union -from typing import cast +from typing import Any, Dict, List, Tuple, Union, cast from docutils import nodes from docutils.nodes import Node @@ -23,8 +22,9 @@ from sphinx.util.typing import TextlikeNode if False: # For type annotation from typing import Type # for python3.5.1 - from sphinx.environment import BuildEnvironment + from sphinx.directive import ObjectDescription + from sphinx.environment import BuildEnvironment def _is_single_paragraph(node: nodes.field_body) -> bool: @@ -295,6 +295,7 @@ class DocFieldTransformer: self.directive.domain, target, contnode=content[0], + env=self.directive.state.document.settings.env ) if _is_single_paragraph(field_body): paragraph = cast(nodes.paragraph, field_body[0]) diff --git a/sphinx/util/docstrings.py b/sphinx/util/docstrings.py index 64fdbf1d7..ac778af87 100644 --- a/sphinx/util/docstrings.py +++ b/sphinx/util/docstrings.py @@ -4,7 +4,7 @@ Utilities for docstring processing. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -17,7 +17,6 @@ from docutils.parsers.rst.states import Body from sphinx.deprecation import RemovedInSphinx50Warning - field_list_item_re = re.compile(Body.patterns['field_marker']) @@ -57,7 +56,7 @@ def prepare_docstring(s: str, ignore: int = None, tabsize: int = 8) -> List[str] if ignore is None: ignore = 1 else: - warnings.warn("The 'ignore' argument to parepare_docstring() is deprecated.", + warnings.warn("The 'ignore' argument to prepare_docstring() is deprecated.", RemovedInSphinx50Warning, stacklevel=2) lines = s.expandtabs(tabsize).splitlines() diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 972db3520..ce50c7ab1 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -4,7 +4,7 @@ Utility functions for docutils. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -15,8 +15,7 @@ from copy import copy from distutils.version import LooseVersion from os import path from types import ModuleType -from typing import Any, Callable, Dict, Generator, IO, List, Optional, Set, Tuple -from typing import cast +from typing import IO, Any, Callable, Dict, Generator, List, Optional, Set, Tuple, cast import docutils from docutils import nodes @@ -24,7 +23,7 @@ from docutils.io import FileOutput from docutils.nodes import Element, Node, system_message from docutils.parsers.rst import Directive, directives, roles from docutils.parsers.rst.states import Inliner -from docutils.statemachine import StateMachine, State, StringList +from docutils.statemachine import State, StateMachine, StringList from docutils.utils import Reporter, unescape from sphinx.errors import SphinxError @@ -37,6 +36,7 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/( if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.builders import Builder from sphinx.config import Config from sphinx.environment import BuildEnvironment @@ -459,7 +459,7 @@ class SphinxTranslator(nodes.NodeVisitor): The priority of visitor method is: 1. ``self.visit_{node_class}()`` - 2. ``self.visit_{supre_node_class}()`` + 2. ``self.visit_{super_node_class}()`` 3. ``self.unknown_visit()`` """ for node_class in node.__class__.__mro__: @@ -497,7 +497,7 @@ def new_document(source_path: str, settings: Any = None) -> nodes.document: """Return a new empty document object. This is an alternative of docutils'. This is a simple wrapper for ``docutils.utils.new_document()``. It - caches the result of docutils' and use it on second call for instanciation. + caches the result of docutils' and use it on second call for instantiation. This makes an instantiation of document nodes much faster. """ global __document_cache__ @@ -509,6 +509,7 @@ def new_document(source_path: str, settings: Any = None) -> nodes.document: settings = copy(__document_cache__.settings) # Create a new instance of nodes.document using cached reporter - document = nodes.document(settings, __document_cache__.reporter, source=source_path) + from sphinx import addnodes + document = addnodes.document(settings, __document_cache__.reporter, source=source_path) document.note_source(source_path, -1) return document diff --git a/sphinx/util/fileutil.py b/sphinx/util/fileutil.py index d8e896d48..466c28135 100644 --- a/sphinx/util/fileutil.py +++ b/sphinx/util/fileutil.py @@ -4,13 +4,13 @@ File utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import posixpath -from typing import Dict +from typing import Callable, Dict from docutils.utils import relative_path @@ -56,7 +56,8 @@ def copy_asset_file(source: str, destination: str, def copy_asset(source: str, destination: str, excluded: PathMatcher = lambda path: False, - context: Dict = None, renderer: "BaseRenderer" = None) -> None: + context: Dict = None, renderer: "BaseRenderer" = None, + onerror: Callable[[str, Exception], None] = None) -> None: """Copy asset files to destination recursively. On copying, it expands the template variables if context argument is given and @@ -67,6 +68,7 @@ def copy_asset(source: str, destination: str, excluded: PathMatcher = lambda pat :param excluded: The matcher to determine the given path should be copied or not :param context: The template variables. If not given, template files are simply copied :param renderer: The template engine. If not given, SphinxRenderer is used by default + :param onerror: The error handler. """ if not os.path.exists(source): return @@ -90,6 +92,12 @@ def copy_asset(source: str, destination: str, excluded: PathMatcher = lambda pat for filename in files: if not excluded(posixpath.join(reldir, filename)): - copy_asset_file(posixpath.join(root, filename), - posixpath.join(destination, reldir), - context, renderer) + try: + copy_asset_file(posixpath.join(root, filename), + posixpath.join(destination, reldir), + context, renderer) + except Exception as exc: + if onerror: + onerror(posixpath.join(root, filename), exc) + else: + raise diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index 1cb75637c..8341dfffe 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -4,7 +4,7 @@ Builder superclass for all builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import gettext @@ -14,7 +14,7 @@ import warnings from collections import namedtuple from datetime import datetime, timezone from os import path -from typing import Callable, Generator, List, Set, Tuple +from typing import Callable, Generator, List, Set, Tuple, Union import babel.dates from babel.messages.mofile import write_mo @@ -34,7 +34,7 @@ if False: logger = logging.getLogger(__name__) -LocaleFileInfoBase = namedtuple('CatalogInfo', 'base_dir,domain,charset') +LocaleFileInfoBase = namedtuple('LocaleFileInfoBase', 'base_dir,domain,charset') class CatalogInfo(LocaleFileInfoBase): @@ -128,8 +128,10 @@ def find_catalog(docname: str, compaction: bool) -> str: return ret -def docname_to_domain(docname: str, compation: bool) -> str: +def docname_to_domain(docname: str, compation: Union[bool, str]) -> str: """Convert docname to domain for catalogs.""" + if isinstance(compation, str): + return compation if compation: return docname.split(SEP, 1)[0] else: @@ -234,7 +236,9 @@ date_format_mappings = { '%X': 'medium', # Locale’s appropriate time representation. '%y': 'YY', # Year without century as a zero-padded decimal number. '%Y': 'yyyy', # Year with century as a decimal number. - '%Z': 'zzzz', # Time zone name (no characters if no time zone exists). + '%Z': 'zzz', # Time zone name (no characters if no time zone exists). + '%z': 'ZZZ', # UTC offset in the form ±HHMM[SS[.ffffff]] + # (empty string if the object is naive). '%%': '%', } @@ -306,13 +310,17 @@ def get_image_filename_for_language(filename: str, env: "BuildEnvironment") -> s dirname = path.dirname(d['root']) if dirname and not dirname.endswith(path.sep): dirname += path.sep + docpath = path.dirname(env.docname) + if docpath and not docpath.endswith(path.sep): + docpath += path.sep d['path'] = dirname d['basename'] = path.basename(d['root']) + d['docpath'] = docpath d['language'] = env.config.language try: return filename_format.format(**d) except KeyError as exc: - raise SphinxError('Invalid figure_language_filename: %r' % exc) + raise SphinxError('Invalid figure_language_filename: %r' % exc) from exc def search_image_for_language(filename: str, env: "BuildEnvironment") -> str: @@ -320,8 +328,8 @@ def search_image_for_language(filename: str, env: "BuildEnvironment") -> str: return filename translated = get_image_filename_for_language(filename, env) - dirname = path.dirname(env.docname) - if path.exists(path.join(env.srcdir, dirname, translated)): + _, abspath = env.relfn2path(translated) + if path.exists(abspath): return translated else: return filename diff --git a/sphinx/util/images.py b/sphinx/util/images.py index 115007d31..81a321818 100644 --- a/sphinx/util/images.py +++ b/sphinx/util/images.py @@ -4,7 +4,7 @@ Image utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -54,7 +54,7 @@ def get_image_size(filename: str) -> Optional[Tuple[int, int]]: def guess_mimetype_for_stream(stream: IO, default: Optional[str] = None) -> Optional[str]: - imgtype = imghdr.what(stream) # type: ignore + imgtype = imghdr.what(stream) if imgtype: return 'image/' + imgtype else: diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 0f3f47562..202e170c1 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -4,11 +4,12 @@ Helpers for inspecting Python modules. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import builtins +import contextlib import enum import inspect import re @@ -17,30 +18,28 @@ import types import typing import warnings from functools import partial, partialmethod -from inspect import ( # NOQA - Parameter, isclass, ismethod, ismethoddescriptor -) +from inspect import Parameter, isclass, ismethod, ismethoddescriptor, ismodule # NOQA from io import StringIO -from typing import Any, Callable, Mapping, List, Optional, Tuple -from typing import cast +from typing import Any, Callable, Dict, List, Mapping, Optional, Sequence, Tuple, cast from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.pycode.ast import ast # for py35-37 from sphinx.pycode.ast import unparse as ast_unparse from sphinx.util import logging +from sphinx.util.typing import ForwardRef from sphinx.util.typing import stringify as stringify_annotation if sys.version_info > (3, 7): - from types import ( - ClassMethodDescriptorType, - MethodDescriptorType, - WrapperDescriptorType - ) + from types import ClassMethodDescriptorType, MethodDescriptorType, WrapperDescriptorType else: ClassMethodDescriptorType = type(object.__init__) MethodDescriptorType = type(str.join) WrapperDescriptorType = type(dict.__dict__['fromkeys']) +if False: + # For type annotation + from typing import Type # NOQA + logger = logging.getLogger(__name__) memory_address_re = re.compile(r' at 0x[0-9a-f]{8,16}(?=>)', re.IGNORECASE) @@ -60,14 +59,6 @@ def getargspec(func: Callable) -> Any: methods.""" warnings.warn('sphinx.ext.inspect.getargspec() is deprecated', RemovedInSphinx50Warning, stacklevel=2) - # On 3.5+, signature(int) or similar raises ValueError. On 3.4, it - # succeeds with a bogus signature. We want a TypeError uniformly, to - # match historical behavior. - if (isinstance(func, type) and - is_builtin_class_method(func, "__new__") and - is_builtin_class_method(func, "__init__")): - raise TypeError( - "can't compute signature for built-in type {}".format(func)) sig = inspect.signature(func) @@ -120,7 +111,11 @@ def getargspec(func: Callable) -> Any: def unwrap(obj: Any) -> Any: """Get an original object from wrapped object (wrapped functions).""" try: - return inspect.unwrap(obj) + if hasattr(obj, '__sphinx_mock__'): + # Skip unwrapping mock object to avoid RecursionError + return obj + else: + return inspect.unwrap(obj) except ValueError: # might be a mock object return obj @@ -146,6 +141,81 @@ def unwrap_all(obj: Any, *, stop: Callable = None) -> Any: return obj +def getall(obj: Any) -> Optional[Sequence[str]]: + """Get __all__ attribute of the module as dict. + + Return None if given *obj* does not have __all__. + Raises AttributeError if given *obj* raises an error on accessing __all__. + Raises ValueError if given *obj* have invalid __all__. + """ + __all__ = safe_getattr(obj, '__all__', None) + if __all__ is None: + return None + else: + if (isinstance(__all__, (list, tuple)) and all(isinstance(e, str) for e in __all__)): + return __all__ + else: + raise ValueError(__all__) + + +def getannotations(obj: Any) -> Mapping[str, Any]: + """Get __annotations__ from given *obj* safely. + + Raises AttributeError if given *obj* raises an error on accessing __attribute__. + """ + __annotations__ = safe_getattr(obj, '__annotations__', None) + if isinstance(__annotations__, Mapping): + return __annotations__ + else: + return {} + + +def getmro(obj: Any) -> Tuple["Type", ...]: + """Get __mro__ from given *obj* safely. + + Raises AttributeError if given *obj* raises an error on accessing __mro__. + """ + __mro__ = safe_getattr(obj, '__mro__', None) + if isinstance(__mro__, tuple): + return __mro__ + else: + return tuple() + + +def getslots(obj: Any) -> Optional[Dict]: + """Get __slots__ attribute of the class as dict. + + Return None if gienv *obj* does not have __slots__. + Raises AttributeError if given *obj* raises an error on accessing __slots__. + Raises TypeError if given *obj* is not a class. + Raises ValueError if given *obj* have invalid __slots__. + """ + if not inspect.isclass(obj): + raise TypeError + + __slots__ = safe_getattr(obj, '__slots__', None) + if __slots__ is None: + return None + elif isinstance(__slots__, dict): + return __slots__ + elif isinstance(__slots__, str): + return {__slots__: None} + elif isinstance(__slots__, (list, tuple)): + return {e: None for e in __slots__} + else: + raise ValueError + + +def isNewType(obj: Any) -> bool: + """Check the if object is a kind of NewType.""" + __module__ = safe_getattr(obj, '__module__', None) + __qualname__ = safe_getattr(obj, '__qualname__', None) + if __module__ == 'typing' and __qualname__ == 'NewType.<locals>.new_type': + return True + else: + return False + + def isenumclass(x: Any) -> bool: """Check if the object is subclass of enum.""" return inspect.isclass(x) and issubclass(x, enum.Enum) @@ -302,6 +372,11 @@ def iscoroutinefunction(obj: Any) -> bool: def isproperty(obj: Any) -> bool: """Check if the object is property.""" + if sys.version_info >= (3, 8): + from functools import cached_property # cached_property is available since py3.8 + if isinstance(obj, cached_property): + return True + return isinstance(obj, property) @@ -313,6 +388,9 @@ def isgenericalias(obj: Any) -> bool: elif (hasattr(types, 'GenericAlias') and # only for py39+ isinstance(obj, types.GenericAlias)): # type: ignore return True + elif (hasattr(typing, '_SpecialGenericAlias') and # for py39+ + isinstance(obj, typing._SpecialGenericAlias)): # type: ignore + return True else: return False @@ -321,7 +399,7 @@ def safe_getattr(obj: Any, name: str, *defargs: Any) -> Any: """A getattr() that turns all exceptions into AttributeErrors.""" try: return getattr(obj, name, *defargs) - except Exception: + except Exception as exc: # sometimes accessing a property raises an exception (e.g. # NotImplementedError), so let's try to read the attribute directly try: @@ -336,7 +414,7 @@ def safe_getattr(obj: Any, name: str, *defargs: Any) -> Any: if defargs: return defargs[0] - raise AttributeError(name) + raise AttributeError(name) from exc def safe_getmembers(object: Any, predicate: Callable[[str], bool] = None, @@ -385,8 +463,8 @@ def object_description(object: Any) -> str: for x in sorted_values) try: s = repr(object) - except Exception: - raise ValueError + except Exception as exc: + raise ValueError from exc # Strip non-deterministic memory addresses such as # ``<__main__.A at 0x7f68cb685710>`` s = memory_address_re.sub('', s) @@ -421,17 +499,50 @@ def is_builtin_class_method(obj: Any, attr_name: str) -> bool: return getattr(builtins, name, None) is cls -def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = False - ) -> inspect.Signature: +class DefaultValue: + """A simple wrapper for default value of the parameters of overload functions.""" + + def __init__(self, value: str) -> None: + self.value = value + + def __eq__(self, other: object) -> bool: + return self.value == other + + def __repr__(self) -> str: + return self.value + + +def _should_unwrap(subject: Callable) -> bool: + """Check the function should be unwrapped on getting signature.""" + if (safe_getattr(subject, '__globals__', None) and + subject.__globals__.get('__name__') == 'contextlib' and # type: ignore + subject.__globals__.get('__file__') == contextlib.__file__): # type: ignore + # contextmanger should be unwrapped + return True + + return False + + +def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = None, + type_aliases: Dict = {}) -> inspect.Signature: """Return a Signature object for the given *subject*. :param bound_method: Specify *subject* is a bound method or not :param follow_wrapped: Same as ``inspect.signature()``. - Defaults to ``False`` (get a signature of *subject*). """ + + if follow_wrapped is None: + follow_wrapped = True + else: + warnings.warn('The follow_wrapped argument of sphinx.util.inspect.signature() is ' + 'deprecated', RemovedInSphinx50Warning, stacklevel=2) + try: try: - signature = inspect.signature(subject, follow_wrapped=follow_wrapped) + if _should_unwrap(subject): + signature = inspect.signature(subject) + else: + signature = inspect.signature(subject, follow_wrapped=follow_wrapped) except ValueError: # follow built-in wrappers up (ex. functools.lru_cache) signature = inspect.signature(subject) @@ -448,10 +559,10 @@ def signature(subject: Callable, bound_method: bool = False, follow_wrapped: boo raise try: - # Update unresolved annotations using ``get_type_hints()``. - annotations = typing.get_type_hints(subject) + # Resolve annotations using ``get_type_hints()`` and type_aliases. + annotations = typing.get_type_hints(subject, None, type_aliases) for i, param in enumerate(parameters): - if isinstance(param.annotation, str) and param.name in annotations: + if param.name in annotations: parameters[i] = param.replace(annotation=annotations[param.name]) if 'return' in annotations: return_annotation = annotations['return'] @@ -469,7 +580,60 @@ def signature(subject: Callable, bound_method: bool = False, follow_wrapped: boo if len(parameters) > 0: parameters.pop(0) - return inspect.Signature(parameters, return_annotation=return_annotation) + # To allow to create signature object correctly for pure python functions, + # pass an internal parameter __validate_parameters__=False to Signature + # + # For example, this helps a function having a default value `inspect._empty`. + # refs: https://github.com/sphinx-doc/sphinx/issues/7935 + return inspect.Signature(parameters, return_annotation=return_annotation, # type: ignore + __validate_parameters__=False) + + +def evaluate_signature(sig: inspect.Signature, globalns: Dict = None, localns: Dict = None + ) -> inspect.Signature: + """Evaluate unresolved type annotations in a signature object.""" + def evaluate_forwardref(ref: ForwardRef, globalns: Dict, localns: Dict) -> Any: + """Evaluate a forward reference.""" + if sys.version_info > (3, 9): + return ref._evaluate(globalns, localns, frozenset()) + else: + return ref._evaluate(globalns, localns) + + def evaluate(annotation: Any, globalns: Dict, localns: Dict) -> Any: + """Evaluate unresolved type annotation.""" + try: + if isinstance(annotation, str): + ref = ForwardRef(annotation, True) + annotation = evaluate_forwardref(ref, globalns, localns) + + if isinstance(annotation, ForwardRef): + annotation = evaluate_forwardref(ref, globalns, localns) + elif isinstance(annotation, str): + # might be a ForwardRef'ed annotation in overloaded functions + ref = ForwardRef(annotation, True) + annotation = evaluate_forwardref(ref, globalns, localns) + except (NameError, TypeError): + # failed to evaluate type. skipped. + pass + + return annotation + + if globalns is None: + globalns = {} + if localns is None: + localns = globalns + + parameters = list(sig.parameters.values()) + for i, param in enumerate(parameters): + if param.annotation: + annotation = evaluate(param.annotation, globalns, localns) + parameters[i] = param.replace(annotation=annotation) + + return_annotation = sig.return_annotation + if return_annotation: + return_annotation = evaluate(return_annotation, globalns, localns) + + return sig.replace(parameters=parameters, return_annotation=return_annotation) def stringify_signature(sig: inspect.Signature, show_annotation: bool = True, @@ -526,11 +690,16 @@ def stringify_signature(sig: inspect.Signature, show_annotation: bool = True, def signature_from_str(signature: str) -> inspect.Signature: """Create a Signature object from string.""" - module = ast.parse('def func' + signature + ': pass') - definition = cast(ast.FunctionDef, module.body[0]) # type: ignore + code = 'def func' + signature + ': pass' + module = ast.parse(code) + function = cast(ast.FunctionDef, module.body[0]) # type: ignore + + return signature_from_ast(function, code) + - # parameters - args = definition.args +def signature_from_ast(node: ast.FunctionDef, code: str = '') -> inspect.Signature: + """Create a Signature object from AST *node*.""" + args = node.args defaults = list(args.defaults) params = [] if hasattr(args, "posonlyargs"): @@ -548,9 +717,9 @@ def signature_from_str(signature: str) -> inspect.Signature: if defaults[i] is Parameter.empty: default = Parameter.empty else: - default = ast_unparse(defaults[i]) + default = DefaultValue(ast_unparse(defaults[i], code)) - annotation = ast_unparse(arg.annotation) or Parameter.empty + annotation = ast_unparse(arg.annotation, code) or Parameter.empty params.append(Parameter(arg.arg, Parameter.POSITIONAL_ONLY, default=default, annotation=annotation)) @@ -558,29 +727,29 @@ def signature_from_str(signature: str) -> inspect.Signature: if defaults[i + posonlyargs] is Parameter.empty: default = Parameter.empty else: - default = ast_unparse(defaults[i + posonlyargs]) + default = DefaultValue(ast_unparse(defaults[i + posonlyargs], code)) - annotation = ast_unparse(arg.annotation) or Parameter.empty + annotation = ast_unparse(arg.annotation, code) or Parameter.empty params.append(Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD, default=default, annotation=annotation)) if args.vararg: - annotation = ast_unparse(args.vararg.annotation) or Parameter.empty + annotation = ast_unparse(args.vararg.annotation, code) or Parameter.empty params.append(Parameter(args.vararg.arg, Parameter.VAR_POSITIONAL, annotation=annotation)) for i, arg in enumerate(args.kwonlyargs): - default = ast_unparse(args.kw_defaults[i]) or Parameter.empty - annotation = ast_unparse(arg.annotation) or Parameter.empty + default = ast_unparse(args.kw_defaults[i], code) or Parameter.empty + annotation = ast_unparse(arg.annotation, code) or Parameter.empty params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default, annotation=annotation)) if args.kwarg: - annotation = ast_unparse(args.kwarg.annotation) or Parameter.empty + annotation = ast_unparse(args.kwarg.annotation, code) or Parameter.empty params.append(Parameter(args.kwarg.arg, Parameter.VAR_KEYWORD, annotation=annotation)) - return_annotation = ast_unparse(definition.returns) or Parameter.empty + return_annotation = ast_unparse(node.returns, code) or Parameter.empty return inspect.Signature(params, return_annotation=return_annotation) diff --git a/sphinx/util/inventory.py b/sphinx/util/inventory.py index 9b647ccac..b1af1bfb9 100644 --- a/sphinx/util/inventory.py +++ b/sphinx/util/inventory.py @@ -4,18 +4,17 @@ Inventory utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import re import zlib -from typing import Callable, IO, Iterator +from typing import IO, Callable, Iterator from sphinx.util import logging from sphinx.util.typing import Inventory - BUFSIZE = 16 * 1024 logger = logging.getLogger(__name__) @@ -122,11 +121,16 @@ class InventoryFile: for line in stream.read_compressed_lines(): # be careful to handle names with embedded spaces correctly - m = re.match(r'(?x)(.+?)\s+(\S*:\S*)\s+(-?\d+)\s+?(\S*)\s+(.*)', + m = re.match(r'(?x)(.+?)\s+(\S+)\s+(-?\d+)\s+?(\S*)\s+(.*)', line.rstrip()) if not m: continue name, type, prio, location, dispname = m.groups() + if ':' not in type: + # wrong type value. type should be in the form of "{domain}:{objtype}" + # + # Note: To avoid the regex DoS, this is implemented in python (refs: #8175) + continue if type == 'py:module' and type in invdata and name in invdata[type]: # due to a bug in 1.1 and below, # two inventory entries are created diff --git a/sphinx/util/jsdump.py b/sphinx/util/jsdump.py index 1f0e258cb..114fd7075 100644 --- a/sphinx/util/jsdump.py +++ b/sphinx/util/jsdump.py @@ -5,12 +5,12 @@ This module implements a simple JavaScript serializer. Uses the basestring encode function from simplejson by Bob Ippolito. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re -from typing import Any, Dict, IO, List, Match, Union +from typing import IO, Any, Dict, List, Match, Union _str_re = re.compile(r'"(\\\\|\\"|[^"])*"') _int_re = re.compile(r'\d+') diff --git a/sphinx/util/jsonimpl.py b/sphinx/util/jsonimpl.py index 35501f03a..b038fd4db 100644 --- a/sphinx/util/jsonimpl.py +++ b/sphinx/util/jsonimpl.py @@ -4,18 +4,17 @@ JSON serializer implementation wrapper. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import json import warnings from collections import UserString -from typing import Any, IO +from typing import IO, Any from sphinx.deprecation import RemovedInSphinx40Warning - warnings.warn('sphinx.util.jsonimpl is deprecated', RemovedInSphinx40Warning, stacklevel=2) diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 5889f3860..09780723a 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -4,7 +4,7 @@ Logging utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,7 +12,7 @@ import logging import logging.handlers from collections import defaultdict from contextlib import contextmanager -from typing import Any, Dict, Generator, IO, List, Tuple, Union +from typing import IO, Any, Dict, Generator, List, Tuple, Union from docutils import nodes from docutils.nodes import Node @@ -24,6 +24,7 @@ from sphinx.util.console import colorize if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.application import Sphinx diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py index 2d37866a6..d33ae0333 100644 --- a/sphinx/util/matching.py +++ b/sphinx/util/matching.py @@ -4,7 +4,7 @@ Pattern-matching utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/math.py b/sphinx/util/math.py index 2a9bd66d7..229e09d36 100644 --- a/sphinx/util/math.py +++ b/sphinx/util/math.py @@ -4,7 +4,7 @@ Utility functions for math. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index a18eac580..d5e43e716 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -4,15 +4,14 @@ Docutils node-related utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re import unicodedata import warnings -from typing import Any, Callable, Iterable, List, Set, Tuple -from typing import cast +from typing import Any, Callable, Iterable, List, Set, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node @@ -28,9 +27,11 @@ from sphinx.util import logging if False: # For type annotation from typing import Type # for python3.5.1 + from sphinx.builders import Builder + from sphinx.domain import IndexEntry from sphinx.environment import BuildEnvironment - from sphinx.utils.tags import Tags + from sphinx.util.tags import Tags logger = logging.getLogger(__name__) @@ -241,6 +242,7 @@ def is_translatable(node: Node) -> bool: LITERAL_TYPE_NODES = ( nodes.literal_block, nodes.doctest_block, + nodes.math_block, nodes.raw, ) IMAGE_TYPE_NODES = ( @@ -313,7 +315,7 @@ def get_prev_node(node: Node) -> Node: return None -def traverse_translatable_index(doctree: Element) -> Iterable[Tuple[Element, List[str]]]: +def traverse_translatable_index(doctree: Element) -> Iterable[Tuple[Element, List["IndexEntry"]]]: # NOQA """Traverse translatable index node from a document tree.""" for node in doctree.traverse(NodeMatcher(addnodes.index, inline=False)): # type: addnodes.index # NOQA if 'raw_entries' in node: @@ -467,46 +469,46 @@ def _make_id(string: str) -> str: _non_id_chars = re.compile('[^a-zA-Z0-9._]+') _non_id_at_ends = re.compile('^[-0-9._]+|-+$') _non_id_translate = { - 0x00f8: u'o', # o with stroke - 0x0111: u'd', # d with stroke - 0x0127: u'h', # h with stroke - 0x0131: u'i', # dotless i - 0x0142: u'l', # l with stroke - 0x0167: u't', # t with stroke - 0x0180: u'b', # b with stroke - 0x0183: u'b', # b with topbar - 0x0188: u'c', # c with hook - 0x018c: u'd', # d with topbar - 0x0192: u'f', # f with hook - 0x0199: u'k', # k with hook - 0x019a: u'l', # l with bar - 0x019e: u'n', # n with long right leg - 0x01a5: u'p', # p with hook - 0x01ab: u't', # t with palatal hook - 0x01ad: u't', # t with hook - 0x01b4: u'y', # y with hook - 0x01b6: u'z', # z with stroke - 0x01e5: u'g', # g with stroke - 0x0225: u'z', # z with hook - 0x0234: u'l', # l with curl - 0x0235: u'n', # n with curl - 0x0236: u't', # t with curl - 0x0237: u'j', # dotless j - 0x023c: u'c', # c with stroke - 0x023f: u's', # s with swash tail - 0x0240: u'z', # z with swash tail - 0x0247: u'e', # e with stroke - 0x0249: u'j', # j with stroke - 0x024b: u'q', # q with hook tail - 0x024d: u'r', # r with stroke - 0x024f: u'y', # y with stroke + 0x00f8: 'o', # o with stroke + 0x0111: 'd', # d with stroke + 0x0127: 'h', # h with stroke + 0x0131: 'i', # dotless i + 0x0142: 'l', # l with stroke + 0x0167: 't', # t with stroke + 0x0180: 'b', # b with stroke + 0x0183: 'b', # b with topbar + 0x0188: 'c', # c with hook + 0x018c: 'd', # d with topbar + 0x0192: 'f', # f with hook + 0x0199: 'k', # k with hook + 0x019a: 'l', # l with bar + 0x019e: 'n', # n with long right leg + 0x01a5: 'p', # p with hook + 0x01ab: 't', # t with palatal hook + 0x01ad: 't', # t with hook + 0x01b4: 'y', # y with hook + 0x01b6: 'z', # z with stroke + 0x01e5: 'g', # g with stroke + 0x0225: 'z', # z with hook + 0x0234: 'l', # l with curl + 0x0235: 'n', # n with curl + 0x0236: 't', # t with curl + 0x0237: 'j', # dotless j + 0x023c: 'c', # c with stroke + 0x023f: 's', # s with swash tail + 0x0240: 'z', # z with swash tail + 0x0247: 'e', # e with stroke + 0x0249: 'j', # j with stroke + 0x024b: 'q', # q with hook tail + 0x024d: 'r', # r with stroke + 0x024f: 'y', # y with stroke } _non_id_translate_digraphs = { - 0x00df: u'sz', # ligature sz - 0x00e6: u'ae', # ae - 0x0153: u'oe', # ligature oe - 0x0238: u'db', # db digraph - 0x0239: u'qp', # qp digraph + 0x00df: 'sz', # ligature sz + 0x00e6: 'ae', # ae + 0x0153: 'oe', # ligature oe + 0x0238: 'db', # db digraph + 0x0239: 'qp', # qp digraph } diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index 23f5b0137..53bffd929 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -4,7 +4,7 @@ Operating system-related utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -20,7 +20,7 @@ from io import StringIO from os import path from typing import Any, Generator, Iterator, List, Optional, Tuple -from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning try: # for ALT Linux (#6712) @@ -103,6 +103,9 @@ def mtimes_of_files(dirnames: List[str], suffix: str) -> Iterator[float]: def movefile(source: str, dest: str) -> None: """Move a file, removing the destination if it exists.""" + warnings.warn('sphinx.util.osutil.movefile() is deprecated for removal. ' + 'Please use os.replace() instead.', + RemovedInSphinx50Warning, stacklevel=2) if os.path.exists(dest): try: os.unlink(dest) @@ -168,10 +171,10 @@ def abspath(pathdir: str) -> str: if isinstance(pathdir, bytes): try: pathdir = pathdir.decode(fs_encoding) - except UnicodeDecodeError: + except UnicodeDecodeError as exc: raise UnicodeDecodeError('multibyte filename not supported on ' 'this filesystem encoding ' - '(%r)' % fs_encoding) + '(%r)' % fs_encoding) from exc return pathdir @@ -222,14 +225,14 @@ class FileAvoidWrite: self._io.close() try: - with open(self._path) as old_f: + with open(self._path, encoding='utf-8') as old_f: old_content = old_f.read() if old_content == buf: return except OSError: pass - with open(self._path, 'w') as f: + with open(self._path, 'w', encoding='utf-8') as f: f.write(buf) def __enter__(self) -> "FileAvoidWrite": diff --git a/sphinx/util/parallel.py b/sphinx/util/parallel.py index ddcdaa316..ab27a5128 100644 --- a/sphinx/util/parallel.py +++ b/sphinx/util/parallel.py @@ -4,7 +4,7 @@ Parallel building utilities. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/png.py b/sphinx/util/png.py index 22c35d991..2ab5a836f 100644 --- a/sphinx/util/png.py +++ b/sphinx/util/png.py @@ -4,7 +4,7 @@ PNG image manipulation helpers. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,7 +12,6 @@ import binascii import struct from typing import Optional - LEN_IEND = 12 LEN_DEPTH = 22 diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 6decc1cef..87c38f72e 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -4,7 +4,7 @@ Stuff for Python version compatibility. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -21,7 +21,6 @@ from sphinx.util import logging from sphinx.util.console import terminal_safe from sphinx.util.typing import NoneType - logger = logging.getLogger(__name__) @@ -32,13 +31,13 @@ logger = logging.getLogger(__name__) # support for running 2to3 over config files def convert_with_2to3(filepath: str) -> str: try: - from lib2to3.refactor import RefactoringTool, get_fixers_from_package from lib2to3.pgen2.parse import ParseError - except ImportError: + from lib2to3.refactor import RefactoringTool, get_fixers_from_package + except ImportError as exc: # python 3.9.0a6+ emits PendingDeprecationWarning for lib2to3. # Additionally, removal of the module is still discussed at PEP-594. # To support future python, this catches ImportError for lib2to3. - raise SyntaxError + raise SyntaxError from exc fixers = get_fixers_from_package('lib2to3.fixes') refactoring_tool = RefactoringTool(fixers) @@ -49,7 +48,8 @@ def convert_with_2to3(filepath: str) -> str: # do not propagate lib2to3 exceptions lineno, offset = err.context[1] # try to match ParseError details with SyntaxError details - raise SyntaxError(err.msg, (filepath, lineno, offset, err.value)) + + raise SyntaxError(err.msg, (filepath, lineno, offset, err.value)) from err return str(tree) @@ -90,7 +90,7 @@ def execfile_(filepath: str, _globals: Any, open: Callable = open) -> None: deprecated_alias('sphinx.util.pycompat', { - 'NoneType': NoneType, # type: ignore + 'NoneType': NoneType, 'TextIOWrapper': io.TextIOWrapper, 'htmlescape': html.escape, 'indent': textwrap.indent, @@ -98,4 +98,12 @@ deprecated_alias('sphinx.util.pycompat', 'sys_encoding': sys.getdefaultencoding(), 'u': '', }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'NoneType': 'sphinx.util.typing.NoneType', + 'TextIOWrapper': 'io.TextIOWrapper', + 'htmlescape': 'html.escape', + 'indent': 'textwrap.indent', + 'terminal_safe': 'sphinx.util.console.terminal_safe', + 'sys_encoding': 'sys.getdefaultencoding', + }) diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py index d9d1d1b2c..8ae435d41 100644 --- a/sphinx/util/requests.py +++ b/sphinx/util/requests.py @@ -4,7 +4,7 @@ Simple requests package loader - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -18,6 +18,7 @@ import requests import sphinx from sphinx.config import Config +from sphinx.deprecation import RemovedInSphinx50Warning try: from requests.packages.urllib3.exceptions import SSLError @@ -43,6 +44,10 @@ useragent_header = [('User-Agent', def is_ssl_error(exc: Exception) -> bool: """Check an exception is SSLError.""" + warnings.warn( + "is_ssl_error() is outdated and likely returns incorrect results " + "for modern versions of Requests.", + RemovedInSphinx50Warning) if isinstance(exc, SSLError): return True else: @@ -124,4 +129,4 @@ def head(url: str, **kwargs: Any) -> requests.Response: headers.setdefault('User-Agent', useragent_header[0][1]) with ignore_insecure_warning(**kwargs): - return requests.get(url, **kwargs) + return requests.head(url, **kwargs) diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py index 33acaa0e7..79ede3432 100644 --- a/sphinx/util/rst.py +++ b/sphinx/util/rst.py @@ -4,7 +4,7 @@ reST helper functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -18,12 +18,10 @@ from docutils.parsers.rst import roles from docutils.parsers.rst.languages import en as english from docutils.statemachine import StringList from docutils.utils import Reporter -from jinja2 import Environment -from jinja2 import environmentfilter +from jinja2 import Environment, environmentfilter from sphinx.locale import __ -from sphinx.util import docutils -from sphinx.util import logging +from sphinx.util import docutils, logging logger = logging.getLogger(__name__) @@ -103,6 +101,11 @@ def prepend_prolog(content: StringList, prolog: str) -> None: def append_epilog(content: StringList, epilog: str) -> None: """Append a string to content body as epilog.""" if epilog: - content.append('', '<generated>', 0) + if 0 < len(content): + source, lineno = content.info(-1) + else: + source = '<generated>' + lineno = 0 + content.append('', source, lineno + 1) for lineno, line in enumerate(epilog.splitlines()): content.append(line, '<rst_epilog>', lineno) diff --git a/sphinx/util/smartypants.py b/sphinx/util/smartypants.py index 43f8bc724..ec6b2172c 100644 --- a/sphinx/util/smartypants.py +++ b/sphinx/util/smartypants.py @@ -32,7 +32,6 @@ from docutils.utils import smartquotes from sphinx.util.docutils import __version_info__ as docutils_version - langquotes = {'af': '“”‘’', 'af-x-altquot': '„”‚’', 'bg': '„“‚‘', # Bulgarian, https://bg.wikipedia.org/wiki/Кавички diff --git a/sphinx/util/stemmer/__init__.py b/sphinx/util/stemmer/__init__.py index 94aaa136d..6470dfe2b 100644 --- a/sphinx/util/stemmer/__init__.py +++ b/sphinx/util/stemmer/__init__.py @@ -4,7 +4,7 @@ Word stemming utilities for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/tags.py b/sphinx/util/tags.py index 1662a06f0..c50231220 100644 --- a/sphinx/util/tags.py +++ b/sphinx/util/tags.py @@ -2,7 +2,7 @@ sphinx.util.tags ~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/template.py b/sphinx/util/template.py index 2449a60a1..a61008602 100644 --- a/sphinx/util/template.py +++ b/sphinx/util/template.py @@ -4,7 +4,7 @@ Templates utility functions for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -28,7 +28,7 @@ class BaseRenderer: def __init__(self, loader: BaseLoader = None) -> None: self.env = SandboxedEnvironment(loader=loader, extensions=['jinja2.ext.i18n']) self.env.filters['repr'] = repr - self.env.install_gettext_translations(get_translator()) # type: ignore + self.env.install_gettext_translations(get_translator()) def render(self, template_name: str, context: Dict) -> str: return self.env.get_template(template_name).render(context) @@ -84,6 +84,8 @@ class LaTeXRenderer(SphinxRenderer): self.env.variable_end_string = '%>' self.env.block_start_string = '<%' self.env.block_end_string = '%>' + self.env.comment_start_string = '<#' + self.env.comment_end_string = '#>' class ReSTRenderer(SphinxRenderer): diff --git a/sphinx/util/texescape.py b/sphinx/util/texescape.py index afa1c349e..b67dcfe82 100644 --- a/sphinx/util/texescape.py +++ b/sphinx/util/texescape.py @@ -4,7 +4,7 @@ TeX escaping helper. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,7 +13,6 @@ from typing import Dict from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias - tex_replacements = [ # map TeX special chars ('$', r'\$'), diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py index de92e7593..e85c40cdf 100644 --- a/sphinx/util/typing.py +++ b/sphinx/util/typing.py @@ -4,17 +4,36 @@ The composit types for Sphinx. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import sys import typing -from typing import Any, Callable, Dict, List, Tuple, TypeVar, Union +from struct import Struct +from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, TypeVar, Union from docutils import nodes from docutils.parsers.rst.states import Inliner +if sys.version_info > (3, 7): + from typing import ForwardRef +else: + from typing import _ForwardRef # type: ignore + + class ForwardRef: + """A pseudo ForwardRef class for py35 and py36.""" + def __init__(self, arg: Any, is_argument: bool = True) -> None: + self.arg = arg + + def _evaluate(self, globalns: Dict, localns: Dict) -> Any: + ref = _ForwardRef(self.arg) + return ref._eval_type(globalns, localns) + +if False: + # For type annotation + from typing import Type # NOQA # for python3.5.1 + # An entry of Directive.option_spec DirectiveOption = Callable[[str], Any] @@ -39,27 +58,260 @@ TitleGetter = Callable[[nodes.Node], str] Inventory = Dict[str, Dict[str, Tuple[str, str, str, str]]] +def get_type_hints(obj: Any, globalns: Dict = None, localns: Dict = None) -> Dict[str, Any]: + """Return a dictionary containing type hints for a function, method, module or class object. + + This is a simple wrapper of `typing.get_type_hints()` that does not raise an error on + runtime. + """ + from sphinx.util.inspect import safe_getattr # lazy loading + + try: + return typing.get_type_hints(obj, globalns, localns) + except NameError: + # Failed to evaluate ForwardRef (maybe TYPE_CHECKING) + return safe_getattr(obj, '__annotations__', {}) + except TypeError: + return {} + except KeyError: + # a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084) + return {} + except AttributeError: + # AttributeError is raised on 3.5.2 (fixed by 3.5.3) + return {} + + def is_system_TypeVar(typ: Any) -> bool: """Check *typ* is system defined TypeVar.""" modname = getattr(typ, '__module__', '') - return modname == 'typing' and isinstance(typ, TypeVar) # type: ignore + return modname == 'typing' and isinstance(typ, TypeVar) + + +def restify(cls: Optional["Type"]) -> str: + """Convert python class to a reST reference.""" + from sphinx.util import inspect # lazy loading + + if cls is None or cls is NoneType: + return ':obj:`None`' + elif cls is Ellipsis: + return '...' + elif cls is Struct: + # Before Python 3.9, struct.Struct class has incorrect __module__. + return ':class:`struct.Struct`' + elif inspect.isNewType(cls): + return ':class:`%s`' % cls.__name__ + elif cls.__module__ in ('__builtin__', 'builtins'): + return ':class:`%s`' % cls.__name__ + else: + if sys.version_info >= (3, 7): # py37+ + return _restify_py37(cls) + else: + return _restify_py36(cls) + + +def _restify_py37(cls: Optional["Type"]) -> str: + """Convert python class to a reST reference.""" + from sphinx.util import inspect # lazy loading + + if (inspect.isgenericalias(cls) and + cls.__module__ == 'typing' and cls.__origin__ is Union): + # Union + if len(cls.__args__) > 1 and cls.__args__[-1] is NoneType: + if len(cls.__args__) > 2: + args = ', '.join(restify(a) for a in cls.__args__[:-1]) + return ':obj:`Optional`\\ [:obj:`Union`\\ [%s]]' % args + else: + return ':obj:`Optional`\\ [%s]' % restify(cls.__args__[0]) + else: + args = ', '.join(restify(a) for a in cls.__args__) + return ':obj:`Union`\\ [%s]' % args + elif inspect.isgenericalias(cls): + if getattr(cls, '_name', None): + if cls.__module__ == 'typing': + text = ':class:`%s`' % cls._name + else: + text = ':class:`%s.%s`' % (cls.__module__, cls._name) + else: + text = restify(cls.__origin__) + + if not hasattr(cls, '__args__'): + pass + elif all(is_system_TypeVar(a) for a in cls.__args__): + # Suppress arguments if all system defined TypeVars (ex. Dict[KT, VT]) + pass + elif cls.__module__ == 'typing' and cls._name == 'Callable': + args = ', '.join(restify(a) for a in cls.__args__[:-1]) + text += r"\ [[%s], %s]" % (args, restify(cls.__args__[-1])) + elif cls.__args__: + text += r"\ [%s]" % ", ".join(restify(a) for a in cls.__args__) + + return text + elif hasattr(cls, '__qualname__'): + if cls.__module__ == 'typing': + return ':class:`%s`' % cls.__qualname__ + else: + return ':class:`%s.%s`' % (cls.__module__, cls.__qualname__) + elif hasattr(cls, '_name'): + # SpecialForm + if cls.__module__ == 'typing': + return ':obj:`%s`' % cls._name + else: + return ':obj:`%s.%s`' % (cls.__module__, cls._name) + elif isinstance(cls, ForwardRef): + return ':class:`%s`' % cls.__forward_arg__ + else: + # not a class (ex. TypeVar) + return ':obj:`%s.%s`' % (cls.__module__, cls.__name__) + + +def _restify_py36(cls: Optional["Type"]) -> str: + module = getattr(cls, '__module__', None) + if module == 'typing': + if getattr(cls, '_name', None): + qualname = cls._name + elif getattr(cls, '__qualname__', None): + qualname = cls.__qualname__ + elif getattr(cls, '__forward_arg__', None): + qualname = cls.__forward_arg__ + elif getattr(cls, '__origin__', None): + qualname = stringify(cls.__origin__) # ex. Union + else: + qualname = repr(cls).replace('typing.', '') + elif hasattr(cls, '__qualname__'): + qualname = '%s.%s' % (module, cls.__qualname__) + else: + qualname = repr(cls) + + if (isinstance(cls, typing.TupleMeta) and # type: ignore + not hasattr(cls, '__tuple_params__')): # for Python 3.6 + params = cls.__args__ + if params: + param_str = ', '.join(restify(p) for p in params) + return ':class:`%s`\\ [%s]' % (qualname, param_str) + else: + return ':class:`%s`' % qualname + elif isinstance(cls, typing.GenericMeta): + params = None + if hasattr(cls, '__args__'): + # for Python 3.5.2+ + if cls.__args__ is None or len(cls.__args__) <= 2: # type: ignore # NOQA + params = cls.__args__ # type: ignore + elif cls.__origin__ == Generator: # type: ignore + params = cls.__args__ # type: ignore + else: # typing.Callable + args = ', '.join(restify(arg) for arg in cls.__args__[:-1]) # type: ignore + result = restify(cls.__args__[-1]) # type: ignore + return ':class:`%s`\\ [[%s], %s]' % (qualname, args, result) + elif hasattr(cls, '__parameters__'): + # for Python 3.5.0 and 3.5.1 + params = cls.__parameters__ # type: ignore + + if params: + param_str = ', '.join(restify(p) for p in params) + return ':class:`%s`\\ [%s]' % (qualname, param_str) + else: + return ':class:`%s`' % qualname + elif (hasattr(typing, 'UnionMeta') and + isinstance(cls, typing.UnionMeta) and # type: ignore + hasattr(cls, '__union_params__')): # for Python 3.5 + params = cls.__union_params__ + if params is not None: + if len(params) == 2 and params[1] is NoneType: + return ':obj:`Optional`\\ [%s]' % restify(params[0]) + else: + param_str = ', '.join(restify(p) for p in params) + return ':obj:`%s`\\ [%s]' % (qualname, param_str) + else: + return ':obj:`%s`' % qualname + elif (hasattr(cls, '__origin__') and + cls.__origin__ is typing.Union): # for Python 3.5.2+ + params = cls.__args__ + if params is not None: + if len(params) > 1 and params[-1] is NoneType: + if len(params) > 2: + param_str = ", ".join(restify(p) for p in params[:-1]) + return ':obj:`Optional`\\ [:obj:`Union`\\ [%s]]' % param_str + else: + return ':obj:`Optional`\\ [%s]' % restify(params[0]) + else: + param_str = ', '.join(restify(p) for p in params) + return ':obj:`Union`\\ [%s]' % param_str + else: + return ':obj:`Union`' + elif (isinstance(cls, typing.CallableMeta) and # type: ignore + getattr(cls, '__args__', None) is not None and + hasattr(cls, '__result__')): # for Python 3.5 + # Skipped in the case of plain typing.Callable + args = cls.__args__ + if args is None: + return qualname + elif args is Ellipsis: + args_str = '...' + else: + formatted_args = (restify(a) for a in args) # type: ignore + args_str = '[%s]' % ', '.join(formatted_args) + + return ':class:`%s`\\ [%s, %s]' % (qualname, args_str, stringify(cls.__result__)) + elif (isinstance(cls, typing.TupleMeta) and # type: ignore + hasattr(cls, '__tuple_params__') and + hasattr(cls, '__tuple_use_ellipsis__')): # for Python 3.5 + params = cls.__tuple_params__ + if params is not None: + param_strings = [restify(p) for p in params] + if cls.__tuple_use_ellipsis__: + param_strings.append('...') + return ':class:`%s`\\ [%s]' % (qualname, ', '.join(param_strings)) + else: + return ':class:`%s`' % qualname + elif hasattr(cls, '__qualname__'): + if cls.__module__ == 'typing': + return ':class:`%s`' % cls.__qualname__ + else: + return ':class:`%s.%s`' % (cls.__module__, cls.__qualname__) + elif hasattr(cls, '_name'): + # SpecialForm + if cls.__module__ == 'typing': + return ':obj:`%s`' % cls._name + else: + return ':obj:`%s.%s`' % (cls.__module__, cls._name) + elif hasattr(cls, '__name__'): + # not a class (ex. TypeVar) + return ':obj:`%s.%s`' % (cls.__module__, cls.__name__) + else: + # others (ex. Any) + if cls.__module__ == 'typing': + return ':obj:`%s`' % qualname + else: + return ':obj:`%s.%s`' % (cls.__module__, qualname) def stringify(annotation: Any) -> str: """Stringify type annotation object.""" + from sphinx.util import inspect # lazy loading + if isinstance(annotation, str): - return annotation - elif isinstance(annotation, TypeVar): # type: ignore + if annotation.startswith("'") and annotation.endswith("'"): + # might be a double Forward-ref'ed type. Go unquoting. + return annotation[1:-1] + else: + return annotation + elif isinstance(annotation, TypeVar): + return annotation.__name__ + elif inspect.isNewType(annotation): + # Could not get the module where it defiend return annotation.__name__ elif not annotation: return repr(annotation) - elif annotation is NoneType: # type: ignore + elif annotation is NoneType: return 'None' elif (getattr(annotation, '__module__', None) == 'builtins' and hasattr(annotation, '__qualname__')): return annotation.__qualname__ elif annotation is Ellipsis: return '...' + elif annotation is Struct: + # Before Python 3.9, struct.Struct class has incorrect __module__. + return 'struct.Struct' if sys.version_info >= (3, 7): # py37+ return _stringify_py37(annotation) @@ -90,8 +342,11 @@ def _stringify_py37(annotation: Any) -> str: return repr(annotation) if getattr(annotation, '__args__', None): - if qualname == 'Union': - if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType: # type: ignore # NOQA + if not isinstance(annotation.__args__, (list, tuple)): + # broken __args__ found + pass + elif qualname == 'Union': + if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType: if len(annotation.__args__) > 2: args = ', '.join(stringify(a) for a in annotation.__args__[:-1]) return 'Optional[Union[%s]]' % args @@ -149,6 +404,8 @@ def _stringify_py36(annotation: Any) -> str: # for Python 3.5.2+ if annotation.__args__ is None or len(annotation.__args__) <= 2: # type: ignore # NOQA params = annotation.__args__ # type: ignore + elif annotation.__origin__ == Generator: # type: ignore + params = annotation.__args__ # type: ignore else: # typing.Callable args = ', '.join(stringify(arg) for arg in annotation.__args__[:-1]) # type: ignore @@ -165,7 +422,7 @@ def _stringify_py36(annotation: Any) -> str: hasattr(annotation, '__union_params__')): # for Python 3.5 params = annotation.__union_params__ if params is not None: - if len(params) == 2 and params[1] is NoneType: # type: ignore + if len(params) == 2 and params[1] is NoneType: return 'Optional[%s]' % stringify(params[0]) else: param_str = ', '.join(stringify(p) for p in params) @@ -174,7 +431,7 @@ def _stringify_py36(annotation: Any) -> str: annotation.__origin__ is typing.Union): # for Python 3.5.2+ params = annotation.__args__ if params is not None: - if len(params) > 1 and params[-1] is NoneType: # type: ignore + if len(params) > 1 and params[-1] is NoneType: if len(params) > 2: param_str = ", ".join(stringify(p) for p in params[:-1]) return 'Optional[Union[%s]]' % param_str diff --git a/sphinx/versioning.py b/sphinx/versioning.py index 502bf361c..6e5a9eb26 100644 --- a/sphinx/versioning.py +++ b/sphinx/versioning.py @@ -5,7 +5,7 @@ Implements the low-level algorithms Sphinx uses for the versioning of doctrees. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pickle @@ -116,7 +116,7 @@ def merge_doctrees(old: Node, new: Node, condition: Any) -> Iterator[Node]: def get_ratio(old: str, new: str) -> float: - """Return a "similiarity ratio" (in percent) representing the similarity + """Return a "similarity ratio" (in percent) representing the similarity between the two strings where 0 is equal and anything above less than equal. """ if not all([old, new]): diff --git a/sphinx/writers/__init__.py b/sphinx/writers/__init__.py index 97543df0d..34a5d36f3 100644 --- a/sphinx/writers/__init__.py +++ b/sphinx/writers/__init__.py @@ -4,6 +4,6 @@ Custom docutils writers. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index 85eeb4376..e4da7d857 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -4,7 +4,7 @@ docutils writers handling Sphinx' custom nodes. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,17 +13,17 @@ import os import posixpath import re import warnings -from typing import Any, Iterable, Tuple -from typing import cast +from typing import Any, Iterable, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node, Text -from docutils.writers.html4css1 import Writer, HTMLTranslator as BaseTranslator +from docutils.writers.html4css1 import HTMLTranslator as BaseTranslator +from docutils.writers.html4css1 import Writer from sphinx import addnodes from sphinx.builders import Builder -from sphinx.deprecation import RemovedInSphinx40Warning -from sphinx.locale import admonitionlabels, _, __ +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning +from sphinx.locale import _, __, admonitionlabels from sphinx.util import logging from sphinx.util.docutils import SphinxTranslator from sphinx.util.images import get_image_size @@ -100,11 +100,6 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): self.docnames = [self.builder.current_docname] # for singlehtml builder self.manpages_url = self.config.manpages_url self.protect_literal_text = 0 - self.permalink_text = self.config.html_add_permalinks - # support backwards-compatible setting to a bool - if not isinstance(self.permalink_text, str): - self.permalink_text = '¶' if self.permalink_text else '' - self.permalink_text = self.encode(self.permalink_text) self.secnumber_suffix = self.config.html_secnumber_suffix self.param_separator = '' self.optional_param_level = 0 @@ -315,7 +310,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): if figure_id in self.builder.fignumbers.get(key, {}): self.body.append('<span class="caption-number">') - prefix = self.builder.config.numfig_format.get(figtype) + prefix = self.config.numfig_format.get(figtype) if prefix is None: msg = __('numfig_format is not defined for %s') % figtype logger.warning(msg) @@ -333,9 +328,10 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): append_fignumber(figtype, node['ids'][0]) def add_permalink_ref(self, node: Element, title: str) -> None: - if node['ids'] and self.permalink_text and self.builder.add_permalinks: + if node['ids'] and self.config.html_permalinks and self.builder.add_permalinks: format = '<a class="headerlink" href="#%s" title="%s">%s</a>' - self.body.append(format % (node['ids'][0], title, self.permalink_text)) + self.body.append(format % (node['ids'][0], title, + self.config.html_permalinks_icon)) def generate_targets_for_listing(self, node: Element) -> None: """Generate hyperlink targets for listings. @@ -410,7 +406,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): def depart_title(self, node: Element) -> None: close_tag = self.context[-1] - if (self.permalink_text and self.builder.add_permalinks and + if (self.config.html_permalinks and self.builder.add_permalinks and node.parent.hasattr('ids') and node.parent['ids']): # add permalink anchor if close_tag.startswith('</h'): @@ -420,7 +416,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): node.parent['ids'][0] + 'title="%s">%s' % ( _('Permalink to this headline'), - self.permalink_text)) + self.config.html_permalinks_icon)) elif isinstance(node.parent, nodes.table): self.body.append('</span>') self.add_permalink_ref(node.parent, _('Permalink to this table')) @@ -439,15 +435,14 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): linenos = node.get('linenos', False) highlight_args = node.get('highlight_args', {}) highlight_args['force'] = node.get('force', False) - if lang is self.builder.config.highlight_language: - # only pass highlighter options for original language - opts = self.builder.config.highlight_options - else: - opts = {} + opts = self.config.highlight_options.get(lang, {}) + + if linenos and self.config.html_codeblock_linenos_style: + linenos = self.config.html_codeblock_linenos_style highlighted = self.highlighter.highlight_block( node.rawsource, lang, opts=opts, linenos=linenos, - location=(self.builder.current_docname, node.line), **highlight_args + location=node, **highlight_args ) starttag = self.starttag(node, 'div', suffix='', CLASS='highlight-%s notranslate' % lang) @@ -839,3 +834,9 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): def unknown_visit(self, node: Node) -> None: raise NotImplementedError('Unknown node: ' + node.__class__.__name__) + + @property + def permalink_text(self) -> str: + warnings.warn('HTMLTranslator.permalink_text is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + return self.config.html_permalinks_icon diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 80cedd3bd..12f3f423a 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -4,7 +4,7 @@ Experimental docutils writers for HTML5 handling Sphinx' custom nodes. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,8 +12,7 @@ import os import posixpath import re import warnings -from typing import Any, Iterable, Tuple -from typing import cast +from typing import Any, Iterable, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node, Text @@ -21,8 +20,8 @@ from docutils.writers.html5_polyglot import HTMLTranslator as BaseTranslator from sphinx import addnodes from sphinx.builders import Builder -from sphinx.deprecation import RemovedInSphinx40Warning -from sphinx.locale import admonitionlabels, _, __ +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning +from sphinx.locale import _, __, admonitionlabels from sphinx.util import logging from sphinx.util.docutils import SphinxTranslator from sphinx.util.images import get_image_size @@ -72,11 +71,6 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): self.docnames = [self.builder.current_docname] # for singlehtml builder self.manpages_url = self.config.manpages_url self.protect_literal_text = 0 - self.permalink_text = self.config.html_add_permalinks - # support backwards-compatible setting to a bool - if not isinstance(self.permalink_text, str): - self.permalink_text = '¶' if self.permalink_text else '' - self.permalink_text = self.encode(self.permalink_text) self.secnumber_suffix = self.config.html_secnumber_suffix self.param_separator = '' self.optional_param_level = 0 @@ -287,7 +281,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): if figure_id in self.builder.fignumbers.get(key, {}): self.body.append('<span class="caption-number">') - prefix = self.builder.config.numfig_format.get(figtype) + prefix = self.config.numfig_format.get(figtype) if prefix is None: msg = __('numfig_format is not defined for %s') % figtype logger.warning(msg) @@ -305,9 +299,10 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): append_fignumber(figtype, node['ids'][0]) def add_permalink_ref(self, node: Element, title: str) -> None: - if node['ids'] and self.permalink_text and self.builder.add_permalinks: + if node['ids'] and self.config.html_permalinks and self.builder.add_permalinks: format = '<a class="headerlink" href="#%s" title="%s">%s</a>' - self.body.append(format % (node['ids'][0], title, self.permalink_text)) + self.body.append(format % (node['ids'][0], title, + self.config.html_permalinks_icon)) # overwritten def visit_bullet_list(self, node: Element) -> None: @@ -362,8 +357,8 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): def depart_title(self, node: Element) -> None: close_tag = self.context[-1] - if (self.permalink_text and self.builder.add_permalinks and - node.parent.hasattr('ids') and node.parent['ids']): + if (self.config.html_permalinks and self.builder.add_permalinks and + node.parent.hasattr('ids') and node.parent['ids']): # add permalink anchor if close_tag.startswith('</h'): self.add_permalink_ref(node.parent, _('Permalink to this headline')) @@ -372,7 +367,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): node.parent['ids'][0] + 'title="%s">%s' % ( _('Permalink to this headline'), - self.permalink_text)) + self.config.html_permalinks_icon)) elif isinstance(node.parent, nodes.table): self.body.append('</span>') self.add_permalink_ref(node.parent, _('Permalink to this table')) @@ -391,15 +386,14 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): linenos = node.get('linenos', False) highlight_args = node.get('highlight_args', {}) highlight_args['force'] = node.get('force', False) - if lang is self.builder.config.highlight_language: - # only pass highlighter options for original language - opts = self.builder.config.highlight_options - else: - opts = {} + opts = self.config.highlight_options.get(lang, {}) + + if linenos and self.config.html_codeblock_linenos_style: + linenos = self.config.html_codeblock_linenos_style highlighted = self.highlighter.highlight_block( node.rawsource, lang, opts=opts, linenos=linenos, - location=(self.builder.current_docname, node.line), **highlight_args + location=node, **highlight_args ) starttag = self.starttag(node, 'div', suffix='', CLASS='highlight-%s notranslate' % lang) @@ -788,3 +782,9 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): def unknown_visit(self, node: Node) -> None: raise NotImplementedError('Unknown node: ' + node.__class__.__name__) + + @property + def permalink_text(self) -> str: + warnings.warn('HTMLTranslator.permalink_text is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + return self.config.html_permalinks_icon diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 6e7f5021b..918dda774 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -7,7 +7,7 @@ Much of this code is adapted from Dave Kuhlman's "docpy" writer from his docutils sandbox. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -15,22 +15,19 @@ import re import warnings from collections import defaultdict from os import path -from typing import Any, Dict, Iterable, Iterator, List, Tuple, Set, Union -from typing import cast +from typing import Any, Dict, Iterable, Iterator, List, Set, Tuple, Union, cast from docutils import nodes, writers from docutils.nodes import Element, Node, Text -from sphinx import addnodes -from sphinx import highlighting -from sphinx.deprecation import ( - RemovedInSphinx40Warning, RemovedInSphinx50Warning, deprecated_alias -) +from sphinx import addnodes, highlighting +from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning, + deprecated_alias) from sphinx.domains import IndexEntry from sphinx.domains.std import StandardDomain from sphinx.errors import SphinxError -from sphinx.locale import admonitionlabels, _, __ -from sphinx.util import split_into, logging, texescape +from sphinx.locale import _, __, admonitionlabels +from sphinx.util import logging, split_into, texescape from sphinx.util.docutils import SphinxTranslator from sphinx.util.nodes import clean_astext, get_prev_node from sphinx.util.template import LaTeXRenderer @@ -526,7 +523,7 @@ class LaTeXTranslator(SphinxTranslator): ret = [] # latex_domain_indices can be False/True or a list of index names - indices_config = self.builder.config.latex_domain_indices + indices_config = self.config.latex_domain_indices if indices_config: for domain in self.builder.env.domains.values(): for indexcls in domain.indices: @@ -546,7 +543,7 @@ class LaTeXTranslator(SphinxTranslator): def render(self, template_name: str, variables: Dict) -> str: renderer = LaTeXRenderer(latex_engine=self.config.latex_engine) - for template_dir in self.builder.config.templates_path: + for template_dir in self.config.templates_path: template = path.join(self.builder.confdir, template_dir, template_name) if path.exists(template): @@ -651,7 +648,7 @@ class LaTeXTranslator(SphinxTranslator): if len(node.children) != 1 and not isinstance(node.children[0], nodes.Text): logger.warning(__('document title is not a single Text node'), - location=(self.curfilestack[-1], node.line)) + location=node) if not self.elements['title']: # text needs to be escaped since it is inserted into # the output literally @@ -684,7 +681,7 @@ class LaTeXTranslator(SphinxTranslator): else: logger.warning(__('encountered title node not in section, topic, table, ' 'admonition or sidebar'), - location=(self.curfilestack[-1], node.line or '')) + location=node) self.body.append('\\sphinxstyleothertitle{') self.context.append('}\n') self.in_title = 1 @@ -818,7 +815,8 @@ class LaTeXTranslator(SphinxTranslator): pass def visit_seealso(self, node: Element) -> None: - self.body.append('\n\n\\sphinxstrong{%s:}\n\n' % admonitionlabels['seealso']) + self.body.append('\n\n\\sphinxstrong{%s:}\n\\nopagebreak\n\n' + % admonitionlabels['seealso']) def depart_seealso(self, node: Element) -> None: self.body.append("\n\n") @@ -965,7 +963,7 @@ class LaTeXTranslator(SphinxTranslator): cell = self.table.cell() context = '' if cell.width > 1: - if self.builder.config.latex_use_latex_multicolumn: + if self.config.latex_use_latex_multicolumn: if self.table.col == 0: self.body.append('\\multicolumn{%d}{|l|}{%%\n' % cell.width) else: @@ -1207,7 +1205,6 @@ class LaTeXTranslator(SphinxTranslator): return isinstance(node.parent, nodes.TextElement) def visit_image(self, node: Element) -> None: - attrs = node.attributes pre = [] # type: List[str] # in reverse order post = [] # type: List[str] @@ -1217,27 +1214,27 @@ class LaTeXTranslator(SphinxTranslator): is_inline = self.is_inline(node.parent) else: is_inline = self.is_inline(node) - if 'width' in attrs: - if 'scale' in attrs: - w = self.latex_image_length(attrs['width'], attrs['scale']) + if 'width' in node: + if 'scale' in node: + w = self.latex_image_length(node['width'], node['scale']) else: - w = self.latex_image_length(attrs['width']) + w = self.latex_image_length(node['width']) if w: include_graphics_options.append('width=%s' % w) - if 'height' in attrs: - if 'scale' in attrs: - h = self.latex_image_length(attrs['height'], attrs['scale']) + if 'height' in node: + if 'scale' in node: + h = self.latex_image_length(node['height'], node['scale']) else: - h = self.latex_image_length(attrs['height']) + h = self.latex_image_length(node['height']) if h: include_graphics_options.append('height=%s' % h) - if 'scale' in attrs: + if 'scale' in node: if not include_graphics_options: # if no "width" nor "height", \sphinxincludegraphics will fit # to the available text width if oversized after rescaling. include_graphics_options.append('scale=%s' - % (float(attrs['scale']) / 100.0)) - if 'align' in attrs: + % (float(node['scale']) / 100.0)) + if 'align' in node: align_prepost = { # By default latex aligns the top of an image. (1, 'top'): ('', ''), @@ -1252,8 +1249,8 @@ class LaTeXTranslator(SphinxTranslator): (0, 'right'): ('{\\hspace*{\\fill}', '}'), } try: - pre.append(align_prepost[is_inline, attrs['align']][0]) - post.append(align_prepost[is_inline, attrs['align']][1]) + pre.append(align_prepost[is_inline, node['align']][0]) + post.append(align_prepost[is_inline, node['align']][1]) except KeyError: pass if self.in_parsed_literal: @@ -1545,7 +1542,7 @@ class LaTeXTranslator(SphinxTranslator): id = self.curfilestack[-1] + ':' + uri[1:] self.body.append(self.hyperlink(id)) self.body.append(r'\emph{') - if self.builder.config.latex_show_pagerefs and not \ + if self.config.latex_show_pagerefs and not \ self.in_production_list: self.context.append('}}} (%s)' % self.hyperpageref(id)) else: @@ -1569,8 +1566,7 @@ class LaTeXTranslator(SphinxTranslator): self.body.append(r'\sphinxtermref{') else: self.body.append(r'\sphinxcrossref{') - if self.builder.config.latex_show_pagerefs and not \ - self.in_production_list: + if self.config.latex_show_pagerefs and not self.in_production_list: self.context.append('}}} (%s)' % self.hyperpageref(id)) else: self.context.append('}}}') @@ -1754,15 +1750,11 @@ class LaTeXTranslator(SphinxTranslator): linenos = node.get('linenos', False) highlight_args = node.get('highlight_args', {}) highlight_args['force'] = node.get('force', False) - if lang is self.builder.config.highlight_language: - # only pass highlighter options for original language - opts = self.builder.config.highlight_options - else: - opts = {} + opts = self.config.highlight_options.get(lang, {}) hlcode = self.highlighter.highlight_block( node.rawsource, lang, opts=opts, linenos=linenos, - location=(self.curfilestack[-1], node.line), **highlight_args + location=node, **highlight_args ) if self.in_footnote: self.body.append('\n\\sphinxSetupCodeBlockInFootnote') @@ -1977,7 +1969,8 @@ class LaTeXTranslator(SphinxTranslator): # mainly, %, #, {, } and \ need escaping via a \ escape # in \href, the tilde is allowed and must be represented literally return self.encode(text).replace('\\textasciitilde{}', '~').\ - replace('\\sphinxhyphen{}', '-') + replace('\\sphinxhyphen{}', '-').\ + replace('\\textquotesingle{}', "'") def visit_Text(self, node: Text) -> None: text = self.encode(node.astext()) @@ -2019,12 +2012,12 @@ class LaTeXTranslator(SphinxTranslator): else: from sphinx.util.math import wrap_displaymath self.body.append(wrap_displaymath(node.astext(), label, - self.builder.config.math_number_all)) + self.config.math_number_all)) raise nodes.SkipNode def visit_math_reference(self, node: Element) -> None: label = "equation:%s:%s" % (node['docname'], node['target']) - eqref_format = self.builder.config.math_eqref_format + eqref_format = self.config.math_eqref_format if eqref_format: try: ref = r'\ref{%s}' % label @@ -2089,7 +2082,7 @@ class LaTeXTranslator(SphinxTranslator): warnings.warn('generate_numfig_format() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) ret = [] # type: List[str] - figure = self.builder.config.numfig_format['figure'].split('%s', 1) + figure = self.config.numfig_format['figure'].split('%s', 1) if len(figure) == 1: ret.append('\\def\\fnum@figure{%s}\n' % self.escape(figure[0]).strip()) else: @@ -2100,7 +2093,7 @@ class LaTeXTranslator(SphinxTranslator): self.escape(figure[1])) ret.append('\\makeatother\n') - table = self.builder.config.numfig_format['table'].split('%s', 1) + table = self.config.numfig_format['table'].split('%s', 1) if len(table) == 1: ret.append('\\def\\fnum@table{%s}\n' % self.escape(table[0]).strip()) else: @@ -2111,7 +2104,7 @@ class LaTeXTranslator(SphinxTranslator): self.escape(table[1])) ret.append('\\makeatother\n') - codeblock = self.builder.config.numfig_format['code-block'].split('%s', 1) + codeblock = self.config.numfig_format['code-block'].split('%s', 1) if len(codeblock) == 1: pass # FIXME else: @@ -2127,7 +2120,6 @@ class LaTeXTranslator(SphinxTranslator): from sphinx.builders.latex import constants # NOQA from sphinx.builders.latex.util import ExtBabel # NOQA - deprecated_alias('sphinx.writers.latex', { 'ADDITIONAL_SETTINGS': constants.ADDITIONAL_SETTINGS, @@ -2139,8 +2131,27 @@ deprecated_alias('sphinx.writers.latex', 'XELATEX_GREEK_DEFAULT_FONTPKG': constants.XELATEX_GREEK_DEFAULT_FONTPKG, 'ExtBabel': ExtBabel, }, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, + { + 'ADDITIONAL_SETTINGS': + 'sphinx.builders.latex.constants.ADDITIONAL_SETTINGS', + 'DEFAULT_SETTINGS': + 'sphinx.builders.latex.constants.DEFAULT_SETTINGS', + 'LUALATEX_DEFAULT_FONTPKG': + 'sphinx.builders.latex.constants.LUALATEX_DEFAULT_FONTPKG', + 'PDFLATEX_DEFAULT_FONTPKG': + 'sphinx.builders.latex.constants.PDFLATEX_DEFAULT_FONTPKG', + 'SHORTHANDOFF': + 'sphinx.builders.latex.constants.SHORTHANDOFF', + 'XELATEX_DEFAULT_FONTPKG': + 'sphinx.builders.latex.constants.XELATEX_DEFAULT_FONTPKG', + 'XELATEX_GREEK_DEFAULT_FONTPKG': + 'sphinx.builders.latex.constants.XELATEX_GREEK_DEFAULT_FONTPKG', + 'ExtBabel': 'sphinx.builders.latex.util.ExtBabel', + }) # FIXME: Workaround to avoid circular import # refs: https://github.com/sphinx-doc/sphinx/issues/5433 -from sphinx.builders.latex.nodes import HYPERLINK_SUPPORT_NODES, captioned_literal_block, footnotetext # NOQA +from sphinx.builders.latex.nodes import ( # NOQA isort:skip + HYPERLINK_SUPPORT_NODES, captioned_literal_block, footnotetext, +) diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index 7da2f4e8f..9ef429ba3 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -4,31 +4,27 @@ Manual page writer, extended for Sphinx custom nodes. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import warnings -from typing import Any, Dict, Iterable -from typing import cast +from typing import Any, Dict, Iterable, cast from docutils import nodes from docutils.nodes import Element, Node, TextElement -from docutils.writers.manpage import ( - Writer, - Translator as BaseTranslator -) +from docutils.writers.manpage import Translator as BaseTranslator +from docutils.writers.manpage import Writer from sphinx import addnodes from sphinx.builders import Builder from sphinx.deprecation import RemovedInSphinx40Warning -from sphinx.locale import admonitionlabels, _ +from sphinx.locale import _, admonitionlabels from sphinx.util import logging from sphinx.util.docutils import SphinxTranslator from sphinx.util.i18n import format_date from sphinx.util.nodes import NodeMatcher - logger = logging.getLogger(__name__) @@ -300,8 +296,7 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): if uri.startswith('mailto:') or uri.startswith('http:') or \ uri.startswith('https:') or uri.startswith('ftp:'): # if configured, put the URL after the link - if self.builder.config.man_show_urls and \ - node.astext() != uri: + if self.config.man_show_urls and node.astext() != uri: if uri.startswith('mailto:'): uri = uri[7:] self.body.extend([ diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py index 9c30244e9..6518d10da 100644 --- a/sphinx/writers/texinfo.py +++ b/sphinx/writers/texinfo.py @@ -4,24 +4,26 @@ Custom docutils writer for Texinfo. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re import textwrap +import warnings from os import path -from typing import Any, Dict, Iterable, Iterator, List, Pattern, Set, Tuple, Union -from typing import cast +from typing import (Any, Dict, Iterable, Iterator, List, Optional, Pattern, Set, Tuple, Union, + cast) from docutils import nodes, writers from docutils.nodes import Element, Node, Text -from sphinx import addnodes, __display_version__ +from sphinx import __display_version__, addnodes +from sphinx.deprecation import RemovedInSphinx50Warning from sphinx.domains import IndexEntry from sphinx.domains.index import IndexDomain from sphinx.errors import ExtensionError -from sphinx.locale import admonitionlabels, _, __ +from sphinx.locale import _, __, admonitionlabels from sphinx.util import logging from sphinx.util.docutils import SphinxTranslator from sphinx.util.i18n import format_date @@ -189,6 +191,7 @@ class TexinfoTranslator(SphinxTranslator): self.body = [] # type: List[str] self.context = [] # type: List[str] + self.descs = [] # type: List[addnodes.desc] self.previous_section = None # type: nodes.section self.section_level = 0 self.seen_title = False @@ -230,12 +233,12 @@ class TexinfoTranslator(SphinxTranslator): 'author': self.settings.author, # if empty, use basename of input file 'filename': self.settings.texinfo_filename, - 'release': self.escape(self.builder.config.release), - 'project': self.escape(self.builder.config.project), - 'copyright': self.escape(self.builder.config.copyright), - 'date': self.escape(self.builder.config.today or - format_date(self.builder.config.today_fmt or _('%b %d, %Y'), - language=self.builder.config.language)) + 'release': self.escape(self.config.release), + 'project': self.escape(self.config.project), + 'copyright': self.escape(self.config.copyright), + 'date': self.escape(self.config.today or + format_date(self.config.today_fmt or _('%b %d, %Y'), + language=self.config.language)) }) # title title = self.settings.title # type: str @@ -366,7 +369,7 @@ class TexinfoTranslator(SphinxTranslator): """Return an escaped string suitable for use as an argument to a Texinfo command.""" s = self.escape(s) - # commas are the argument delimeters + # commas are the argument delimiters s = s.replace(',', '@comma{}') # normalize white space s = ' '.join(s.split()).strip() @@ -431,7 +434,7 @@ class TexinfoTranslator(SphinxTranslator): self.add_menu_entries(entries) if (node_name != 'Top' or not self.node_menus[entries[0]] or - self.builder.config.texinfo_no_detailmenu): + self.config.texinfo_no_detailmenu): self.body.append('\n@end menu\n') return @@ -481,7 +484,7 @@ class TexinfoTranslator(SphinxTranslator): ret.append('@end menu\n') return ''.join(ret) - indices_config = self.builder.config.texinfo_domain_indices + indices_config = self.config.texinfo_domain_indices if indices_config: for domain in self.builder.env.domains.values(): for indexcls in domain.indices: @@ -625,7 +628,7 @@ class TexinfoTranslator(SphinxTranslator): elif not isinstance(parent, nodes.section): logger.warning(__('encountered title node not in section, topic, table, ' 'admonition or sidebar'), - location=(self.curfilestack[-1], node.line)) + location=node) self.visit_rubric(node) else: try: @@ -736,7 +739,7 @@ class TexinfoTranslator(SphinxTranslator): else: uri = self.escape_arg(uri) name = self.escape_arg(name) - show_urls = self.builder.config.texinfo_show_urls + show_urls = self.config.texinfo_show_urls if self.in_footnote: show_urls = 'inline' if not name or uri == name: @@ -853,8 +856,8 @@ class TexinfoTranslator(SphinxTranslator): num = node.astext().strip() try: footnode, used = self.footnotestack[-1][num] - except (KeyError, IndexError): - raise nodes.SkipNode + except (KeyError, IndexError) as exc: + raise nodes.SkipNode from exc # footnotes are repeated for each reference footnode.walkabout(self) # type: ignore raise nodes.SkipChildren @@ -1183,7 +1186,7 @@ class TexinfoTranslator(SphinxTranslator): self.body.append('\n@caption{') else: logger.warning(__('caption not inside a figure.'), - location=(self.curfilestack[-1], node.line)) + location=node) def depart_caption(self, node: Element) -> None: if (isinstance(node.parent, nodes.figure) or @@ -1203,11 +1206,10 @@ class TexinfoTranslator(SphinxTranslator): # ignore remote images return name, ext = path.splitext(uri) - attrs = node.attributes # width and height ignored in non-tex output - width = self.tex_image_length(attrs.get('width', '')) - height = self.tex_image_length(attrs.get('height', '')) - alt = self.escape_arg(attrs.get('alt', '')) + width = self.tex_image_length(node.get('width', '')) + height = self.tex_image_length(node.get('height', '')) + alt = self.escape_arg(node.get('alt', '')) filename = "%s-figures/%s" % (self.elements['filename'][:-5], name) # type: ignore self.body.append('\n@image{%s,%s,%s,%s,%s}\n' % (filename, width, height, alt, ext[1:])) @@ -1239,6 +1241,15 @@ class TexinfoTranslator(SphinxTranslator): def depart_legend(self, node: Element) -> None: pass + def visit_substitution_reference(self, node: Element) -> None: + pass + + def depart_substitution_reference(self, node: Element) -> None: + pass + + def visit_substitution_definition(self, node: Element) -> None: + raise nodes.SkipNode + def visit_system_message(self, node: Element) -> None: self.body.append('\n@verbatim\n' '<SYSTEM MESSAGE: %s>\n' @@ -1259,11 +1270,11 @@ class TexinfoTranslator(SphinxTranslator): def unimplemented_visit(self, node: Element) -> None: logger.warning(__("unimplemented node type: %r"), node, - location=(self.curfilestack[-1], node.line)) + location=node) def unknown_visit(self, node: Node) -> None: logger.warning(__("unknown node type: %r"), node, - location=(self.curfilestack[-1], node.line)) + location=node) def unknown_departure(self, node: Node) -> None: pass @@ -1365,12 +1376,12 @@ class TexinfoTranslator(SphinxTranslator): # -- Desc - def visit_desc(self, node: Element) -> None: - self.desc = node + def visit_desc(self, node: addnodes.desc) -> None: + self.descs.append(node) self.at_deffnx = '@deffn' - def depart_desc(self, node: Element) -> None: - self.desc = None + def depart_desc(self, node: addnodes.desc) -> None: + self.descs.pop() self.ensure_eol() self.body.append('@end deffn\n') @@ -1383,9 +1394,8 @@ class TexinfoTranslator(SphinxTranslator): # use the full name of the objtype for the category try: domain = self.builder.env.get_domain(node.parent['domain']) - primary = self.builder.config.primary_domain name = domain.get_type_name(domain.object_types[objtype], - primary == domain.name) + self.config.primary_domain == domain.name) except (KeyError, ExtensionError): name = objtype # by convention, the deffn category should be capitalized like a title @@ -1399,6 +1409,12 @@ class TexinfoTranslator(SphinxTranslator): self.escape_hyphens -= 1 self.desc_type_name = None + def visit_desc_signature_line(self, node: Element) -> None: + pass + + def depart_desc_signature_line(self, node: Element) -> None: + pass + def visit_desc_name(self, node: Element) -> None: pass @@ -1454,9 +1470,8 @@ class TexinfoTranslator(SphinxTranslator): # -- instead of -- # @deffn {Class} class Foo txt = node.astext().strip() - if txt == self.desc['desctype'] or \ - txt == self.desc['objtype'] or \ - txt in self.desc_type_name.split(): + if ((self.descs and txt == self.descs[-1]['objtype']) or + (self.desc_type_name and txt in self.desc_type_name.split())): raise nodes.SkipNode def depart_desc_annotation(self, node: Element) -> None: @@ -1526,3 +1541,11 @@ class TexinfoTranslator(SphinxTranslator): self.body.append('\n\n@example\n%s\n@end example\n\n' % self.escape_arg(node.astext())) raise nodes.SkipNode + + @property + def desc(self) -> Optional[addnodes.desc]: + warnings.warn('TexinfoWriter.desc is deprecated.', RemovedInSphinx50Warning) + if len(self.descs): + return self.descs[-1] + else: + return None diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index b2ccd7b89..c0ebe32a2 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -4,23 +4,22 @@ Custom docutils writer for plain text. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import math import os import re import textwrap -from itertools import groupby, chain -from typing import Any, Dict, Generator, List, Iterable, Optional, Set, Tuple, Union -from typing import cast +from itertools import chain, groupby +from typing import Any, Dict, Generator, Iterable, List, Optional, Set, Tuple, Union, cast from docutils import nodes, writers from docutils.nodes import Element, Node, Text from docutils.utils import column_width from sphinx import addnodes -from sphinx.locale import admonitionlabels, _ +from sphinx.locale import _, admonitionlabels from sphinx.util.docutils import SphinxTranslator if False: @@ -74,7 +73,7 @@ class Table: Cell spanning on multiple rows or multiple columns (having a colspan or rowspan greater than one) are automatically referenced - by all the table cells they covers. This is a usefull + by all the table cells they covers. This is a useful representation as we can simply check ``if self[x, y] is self[x, y+1]`` to recognize a rowspan. @@ -223,7 +222,7 @@ class Table: for left, right in zip(out, out[1:]) ] glue.append(tail) - return head + "".join(chain(*zip(out, glue))) + return head + "".join(chain.from_iterable(zip(out, glue))) for lineno, line in enumerate(self.lines): if self.separator and lineno == self.separator: @@ -1013,6 +1012,9 @@ class TextTranslator(SphinxTranslator): def visit_toctree(self, node: Element) -> None: raise nodes.SkipNode + def visit_substitution_definition(self, node: Element) -> None: + raise nodes.SkipNode + def visit_pending_xref(self, node: Element) -> None: pass diff --git a/sphinx/writers/xml.py b/sphinx/writers/xml.py index d007898ba..19fa3c1ef 100644 --- a/sphinx/writers/xml.py +++ b/sphinx/writers/xml.py @@ -4,7 +4,7 @@ Docutils-native XML and pseudo-XML writers. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/__init__.py diff --git a/tests/certs/cert.pem b/tests/certs/cert.pem new file mode 100644 index 000000000..6f8c35c6b --- /dev/null +++ b/tests/certs/cert.pem @@ -0,0 +1,50 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9fzHGBPNaZNcN +nL/1nvO2xJR/E64vFua3QfPQQ5HpigjrK/HRUlRGztRKJ+CEjCXNYNfQ4dUcV45o +k5uPH3U1CkAw2d/We+kZnAHkNuw4mRC0ohdzpUByyDOA5WtUWPn9SwhXCVz6fM7e +I52auvzpUE6soVDM3nucnqZDJ3Ua9KgB02FrqX13S76Uq+uf8Q2hpTruO/nBzB4p +6xFwJJ1taXEEWi8swg6HO8/+0x0AeripV6JieNUptEFuV9kLvRz9qGg0CO2f7AdI +jNeFDGrgO7qJ+VxXV9Gnbi6ph4vsUwtJZB3phRGGomdgiRd6PSma81nvTe1z69x/ +g+8P091pAgMBAAECggEAIrTABfd0JpMffAPAeJjjJA8+70NIfKFiIiA3Kmalu7Mn +TQMgZ+j/PHS3FtnU2hHc/o+FF2G1KVqz311heUYWrl8xQIE26M6K88DJ6+VPQFJw +Z9TkHK8gbaVTIYFjNfCR4J00atRxLgNb0/2L6QHkPksSDbYB2XPKCfZYlyYL4aKq +dePghFu9ePXhUXooPCqke+kP0b8OmHzPlmJpxbeb8ujiox2+4wYjN8lWPz8xHv8i +IM7V5hAbPIaQfu/joKrRKk+Kk8UqGurkKQ75KLLL+1oaJO/GLTQ4bk5tpRgfWPda +aEBzSPrnqame2CKUWtBughuRWSxdTIMvdXIC/ym1gQKBgQDx6Nyio/L6I5CdlXwC +HAzBCy1mnj70Kj97tQc+A/0z8dD7fCSE/oo8IiEKixcjnaSxHk8VjINF/w17n63W +8neE7pVsuDwxfhiQ9ZRI1WpV0LsFEoTrEWG7Ax8UzbHXCQbNJ9SI0HJRo9UN0f/Z +t+ZT+HNUzdcpCwTvdRVDisbXcQKBgQDIiMz58GFEwdGPXJKEhSyQ3kSQBjeqo0Vl +wMDuDvFEckHl/p1RnDo0lzaq6FivOX84ymvGNdQW14TnQp3A/mkQ5o6k/e1pfAA6 +X0Y6tBH/QppVo5sFvOufyn02k48k5pFAjLHH9L9i0dyWqq4V6PgA2uk4qilFxEg/ +CJEVfq4ZeQKBgQCZPHKWq9f8T48J42kcRPxnRFdMC63BKQnxqOifhhNcVi+VPjw7 +6qlSEiRv80+DBhcPAy4BbnKxYjD+QFX0NL80+5S3u7SVfVS+bnGx+U5UcdYmDmcY +KHiJ6B5GJU4j8tnWFwbwa2ofAPKywHWbSnyicF1OON20aACGVtpTYJM4YQKBgBW4 +09NDGZY0FHoeAfT+4/vxR6X+NmtyciL6hSuETNgoNEEwmmPrs1ZdBtvufSTF6qUB +MDlxPT8YK1pNmf78z+63ur3ej6f8eZ3ZEidruANZeJRMO4+cjj1p1rRhuYC6xQMj ++mH5ff27U9SyOlc/PBYDoH212PCouVaym9yjM0KpAoGBALr583slY55ESOthLrfX +1ecoET5xxRm431XbZMnxu0uUvHWNfqoojtmD7laclb9HwkpShPB6PT1egBIvDWWM +bVUuXzJ8gP0tIG3dHgiiUlld3ahOiaMYSU77uLFBRWv5sQqfewLuFvlzHn/2ZSt7 +TcipT4f67b18W8iuLJELEs57 +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDuTCCAqGgAwIBAgIUUNvkPwe0W8C2I0+KnLpMaQ+S+vowDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCRlIxETAPBgNVBAgMCEJyZXRhZ25lMQ8wDQYDVQQHDAZS +ZW5uZXMxGjAYBgNVBAoMEVNwaGlueCB0ZXN0IHN1aXRlMRIwEAYDVQQDDAlsb2Nh +bGhvc3QwHhcNMjAxMTE1MTcyNDExWhcNMzAxMTEzMTcyNDExWjBhMQswCQYDVQQG +EwJGUjERMA8GA1UECAwIQnJldGFnbmUxDzANBgNVBAcMBlJlbm5lczEaMBgGA1UE +CgwRU3BoaW54IHRlc3Qgc3VpdGUxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAL1/McYE81pk1w2cv/We87bElH8Tri8W +5rdB89BDkemKCOsr8dFSVEbO1Eon4ISMJc1g19Dh1RxXjmiTm48fdTUKQDDZ39Z7 +6RmcAeQ27DiZELSiF3OlQHLIM4Dla1RY+f1LCFcJXPp8zt4jnZq6/OlQTqyhUMze +e5yepkMndRr0qAHTYWupfXdLvpSr65/xDaGlOu47+cHMHinrEXAknW1pcQRaLyzC +Doc7z/7THQB6uKlXomJ41Sm0QW5X2Qu9HP2oaDQI7Z/sB0iM14UMauA7uon5XFdX +0aduLqmHi+xTC0lkHemFEYaiZ2CJF3o9KZrzWe9N7XPr3H+D7w/T3WkCAwEAAaNp +MGcwHQYDVR0OBBYEFN1iHZj88N6eI2FlRzza52xzOU5EMB8GA1UdIwQYMBaAFN1i +HZj88N6eI2FlRzza52xzOU5EMA8GA1UdEwEB/wQFMAMBAf8wFAYDVR0RBA0wC4IJ +bG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBVUZm1iw7N7uZu/SF3hailxS+1 +3KChItWu3ZOIjlmDIkaJ9kWqP2ficUg3tBUx6/UOjHQAwRC4rj87BoSV2mEy+0OX +fyy+ER/BeHYly5v+hpjVojVKeqysk5CKttZM+cOibT2SzLLYf0InNqZRQRJco+nL +QNR0hVo/Lz6Mf1gF2ywf9bXSF3+XECU4K6sVm4QpFbJNm+fHqJBuh1LXHRrcTAsP +LM6PBnd3P5QTcr/G0s/tYMPmero9YHZUO8FMvMVoI2K8k6/duG/EbBaNzriRI1OM +PpZGCWxbJfyApnzc5lGAG4zJnV/wpOyNhKJuW9N1fr2oEwPpJlS3VzrgeKcY +-----END CERTIFICATE----- diff --git a/tests/conftest.py b/tests/conftest.py index 6a08dba76..5580f672b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,7 @@ pytest config for sphinx/tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,8 +13,8 @@ import docutils import pytest import sphinx -from sphinx.testing.path import path from sphinx.testing import comparer +from sphinx.testing.path import path pytest_plugins = 'sphinx.testing.fixtures' diff --git a/tests/ext_napoleon_pep526_data_google.py b/tests/ext_napoleon_pep526_data_google.py new file mode 100644 index 000000000..95e84f470 --- /dev/null +++ b/tests/ext_napoleon_pep526_data_google.py @@ -0,0 +1,18 @@ +""" +Test module for napoleon PEP 526 compatiblity with google style +""" + +module_level_var: int = 99 +"""This is an example module level variable""" + + +class PEP526GoogleClass: + """Sample class with PEP 526 annotations and google docstring + + Attributes: + attr1: Attr1 description. + attr2: Attr2 description. + """ + + attr1: int + attr2: str diff --git a/tests/ext_napoleon_pep526_data_numpy.py b/tests/ext_napoleon_pep526_data_numpy.py new file mode 100644 index 000000000..d13ba31fb --- /dev/null +++ b/tests/ext_napoleon_pep526_data_numpy.py @@ -0,0 +1,22 @@ +""" +Test module for napoleon PEP 526 compatiblity with numpy style +""" + +module_level_var: int = 99 +"""This is an example module level variable""" + + +class PEP526NumpyClass: + """ + Sample class with PEP 526 annotations and numpy docstring + + Attributes + ---------- + attr1: + Attr1 description + + attr2: + Attr2 description + """ + attr1: int + attr2: str diff --git a/tests/roots/test-api-set-translator/conf.py b/tests/roots/test-api-set-translator/conf.py index 15f45a679..671f3905a 100644 --- a/tests/roots/test-api-set-translator/conf.py +++ b/tests/roots/test-api-set-translator/conf.py @@ -11,7 +11,6 @@ from sphinx.writers.manpage import ManualPageTranslator from sphinx.writers.texinfo import TexinfoTranslator from sphinx.writers.text import TextTranslator - project = 'test' diff --git a/tests/roots/test-apidoc-toc/mypackage/main.py b/tests/roots/test-apidoc-toc/mypackage/main.py index 813db805e..c43573a38 100755 --- a/tests/roots/test-apidoc-toc/mypackage/main.py +++ b/tests/roots/test-apidoc-toc/mypackage/main.py @@ -5,7 +5,6 @@ import os import mod_resource import mod_something - if __name__ == "__main__": print("Hello, world! -> something returns: {}".format(mod_something.something())) diff --git a/tests/roots/test-changes/conf.py b/tests/roots/test-changes/conf.py index 9d6d39631..ec67b9c59 100644 --- a/tests/roots/test-changes/conf.py +++ b/tests/roots/test-changes/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- project = 'Sphinx ChangesBuilder tests' -copyright = '2007-2020 by the Sphinx team, see AUTHORS' +copyright = '2007-2021 by the Sphinx team, see AUTHORS' version = '0.6' release = '0.6alpha1' diff --git a/tests/roots/test-circular/conf.py b/tests/roots/test-circular/conf.py index 027d21cda..a45d22e28 100644 --- a/tests/roots/test-circular/conf.py +++ b/tests/roots/test-circular/conf.py @@ -1 +1 @@ -exclude_patterns = ['_build']
+exclude_patterns = ['_build'] diff --git a/tests/roots/test-domain-c-intersphinx/conf.py b/tests/roots/test-domain-c-intersphinx/conf.py new file mode 100644 index 000000000..c176af775 --- /dev/null +++ b/tests/roots/test-domain-c-intersphinx/conf.py @@ -0,0 +1,4 @@ +exclude_patterns = ['_build'] +extensions = [ + 'sphinx.ext.intersphinx', +] diff --git a/tests/roots/test-domain-c-intersphinx/index.rst b/tests/roots/test-domain-c-intersphinx/index.rst new file mode 100644 index 000000000..5d6d3e098 --- /dev/null +++ b/tests/roots/test-domain-c-intersphinx/index.rst @@ -0,0 +1,62 @@ +.. c:member:: void __member = _member + + - :any:`_member` + - :c:member:`_member` + - :c:var:`_member` + - :c:data:`_member` + +.. c:member:: void __var = _var + + - :any:`_var` + - :c:member:`_var` + - :c:var:`_var` + - :c:data:`_var` + +.. c:member:: void __function = _function + + - :any:`_function` + - :c:func:`_function` + - :c:type:`_function` + +.. c:member:: void __macro = _macro + + - :any:`_macro` + - :c:macro:`_macro` + +.. c:type:: _struct __struct + struct _struct __structTagged + + - :any:`_struct` + - :c:struct:`_struct` + - :c:type:`_struct` + +.. c:type:: _union __union + union _union __unionTagged + + - :any:`_union` + - :c:union:`_union` + - :c:type:`_union` + +.. c:type:: _enum __enum + enum _enum __enumTagged + + - :any:`_enum` + - :c:enum:`_enum` + - :c:type:`_enum` + +.. c:member:: void __enumerator = _enumerator + + - :any:`_enumerator` + - :c:enumerator:`_enumerator` + +.. c:type:: _type __type + + - :any:`_type` + - :c:type:`_type` + +.. c:member:: void __functionParam = _functionParam.param + + - :any:`_functionParam.param` + - :c:member:`_functionParam.param` + - :c:var:`_functionParam.param` + - :c:data:`_functionParam.param` diff --git a/tests/roots/test-domain-c/function_param_target.rst b/tests/roots/test-domain-c/function_param_target.rst new file mode 100644 index 000000000..05de01445 --- /dev/null +++ b/tests/roots/test-domain-c/function_param_target.rst @@ -0,0 +1,5 @@ +.. c:function:: void f(int i) + + - :c:var:`i` + +- :c:var:`f.i` diff --git a/tests/roots/test-domain-c/ns_lookup.rst b/tests/roots/test-domain-c/ns_lookup.rst new file mode 100644 index 000000000..87f9d68e7 --- /dev/null +++ b/tests/roots/test-domain-c/ns_lookup.rst @@ -0,0 +1,13 @@ +.. c:namespace:: ns_lookup + +.. c:var:: int i + +.. c:function:: void f(int j) + + - :c:var:`i` + - :c:var:`j` + - :c:expr:`i` + - :c:expr:`j` + +- :c:var:`i` +- :c:expr:`i` diff --git a/tests/roots/test-domain-cpp-intersphinx/conf.py b/tests/roots/test-domain-cpp-intersphinx/conf.py new file mode 100644 index 000000000..c176af775 --- /dev/null +++ b/tests/roots/test-domain-cpp-intersphinx/conf.py @@ -0,0 +1,4 @@ +exclude_patterns = ['_build'] +extensions = [ + 'sphinx.ext.intersphinx', +] diff --git a/tests/roots/test-domain-cpp-intersphinx/index.rst b/tests/roots/test-domain-cpp-intersphinx/index.rst new file mode 100644 index 000000000..9ed9493ed --- /dev/null +++ b/tests/roots/test-domain-cpp-intersphinx/index.rst @@ -0,0 +1,112 @@ +.. cpp:type:: _class __class + + - :any:`_class` + - :cpp:any:`_class` + - :cpp:class:`_class` + - :cpp:struct:`_class` + - :cpp:type:`_class` + +.. cpp:type:: _struct __struct + + - :any:`_struct` + - :cpp:any:`_struct` + - :cpp:class:`_struct` + - :cpp:struct:`_struct` + - :cpp:type:`_struct` + +.. cpp:type:: _union __union + + - :any:`_union` + - :cpp:any:`_union` + - :cpp:union:`_union` + - :cpp:type:`_union` + +.. cpp:member:: void __function = _function + + - :any:`_function` + - :cpp:any:`_function` + - :cpp:func:`_function` + - :cpp:type:`_function` + +.. cpp:member:: void __member = _member + + - :any:`_member` + - :cpp:any:`_member` + - :cpp:member:`_member` + - :cpp:var:`_member` + +.. cpp:member:: void __var = _var + + - :any:`_var` + - :cpp:any:`_var` + - :cpp:member:`_var` + - :cpp:var:`_var` + +.. cpp:type:: _type __type + + - :any:`_type` + - :cpp:any:`_type` + - :cpp:type:`_type` + +.. cpp:function:: template<_concept T> void __concept() + + - :any:`_concept` + - :cpp:any:`_concept` + - :cpp:concept:`_concept` + +.. cpp:type:: _enum __enum + + - :any:`_enum` + - :cpp:any:`_enum` + - :cpp:enum:`_enum` + - :cpp:type:`_enum` + +.. cpp:type:: _enumStruct __enumStruct + + - :any:`_enumStruct` + - :cpp:any:`_enumStruct` + - :cpp:enum:`_enumStruct` + - :cpp:type:`_enumStruct` + +.. cpp:type:: _enumClass __enumClass + + - :any:`_enumClass` + - :cpp:any:`_enumClass` + - :cpp:enum:`_enumClass` + - :cpp:type:`_enumClass` + +.. cpp:member:: void __enumerator = _enumerator + + - :any:`_enumerator` + - :cpp:any:`_enumerator` + - :cpp:enumerator:`_enumerator` + +.. cpp:member:: void __scopedEnumerator = _enumStruct::_scopedEnumerator + + - :any:`_enumStruct::_scopedEnumerator` + - :cpp:any:`_enumStruct::_scopedEnumerator` + - :cpp:enumerator:`_enumStruct::_scopedEnumerator` + +.. cpp:member:: void __enumerator2 = _enum::_enumerator + + - :any:`_enum::_enumerator` + - :cpp:any:`_enum::_enumerator` + - :cpp:enumerator:`_enum::_enumerator` + +.. cpp:member:: void __functionParam = _functionParam::param + + - :any:`_functionParam::param` + - :cpp:any:`_functionParam::param` + - :cpp:member:`_functionParam::param` + - :cpp:var:`_functionParam::param` + +.. cpp:type:: _templateParam::TParam __templateParam + + - :any:`_templateParam::TParam` + - :cpp:any:`_templateParam::TParam` + - :cpp:type:`_templateParam::TParam` + - :cpp:member:`_templateParam::TParam` + - :cpp:var:`_templateParam::TParam` + - :cpp:class:`_templateParam::TParam` + - :cpp:struct:`_templateParam::TParam` + - :cpp:union:`_templateParam::TParam` diff --git a/tests/roots/test-domain-cpp/roles-targets-ok.rst b/tests/roots/test-domain-cpp/roles-targets-ok.rst index e70b9259f..783f7b985 100644 --- a/tests/roots/test-domain-cpp/roles-targets-ok.rst +++ b/tests/roots/test-domain-cpp/roles-targets-ok.rst @@ -123,37 +123,37 @@ :class:`TParamType` :struct:`TParamType` :union:`TParamType` - :func:`TParamType` + function :member:`TParamType` :var:`TParamType` :type:`TParamType` - :concept:`TParamType` - :enum:`TParamType` - :enumerator:`TParamType` + concept + enum + enumerator :cpp:any:`TParamVar` :class:`TParamVar` :struct:`TParamVar` :union:`TParamVar` - :func:`TParamVar` + function :member:`TParamVar` :var:`TParamVar` :type:`TParamVar` - :concept:`TParamVar` - :enum:`TParamVar` - :enumerator:`TParamVar` + concept + enum + enumerator :cpp:any:`TParamTemplate` :class:`TParamTemplate` :struct:`TParamTemplate` :union:`TParamTemplate` - :func:`TParamTemplate` + function :member:`TParamTemplate` :var:`TParamTemplate` :type:`TParamTemplate` - :concept:`TParamTemplate` - :enum:`TParamTemplate` - :enumerator:`TParamTemplate` + concept + enum + enumerator .. function:: void FunctionParams(int FunctionParam) diff --git a/tests/roots/test-domain-cpp/roles-targets-warn.rst b/tests/roots/test-domain-cpp/roles-targets-warn.rst index decebe170..57083ff15 100644 --- a/tests/roots/test-domain-cpp/roles-targets-warn.rst +++ b/tests/roots/test-domain-cpp/roles-targets-warn.rst @@ -114,35 +114,35 @@ class struct union - func + :func:`TParamType` member var type - concept - enum - enumerator + :concept:`TParamType` + :enum:`TParamType` + :enumerator:`TParamType` class struct union - func + :func:`TParamVar` member var type - concept - enum - enumerator + :concept:`TParamVar` + :enum:`TParamVar` + :enumerator:`TParamVar` class struct union - func + :func:`TParamTemplate` member var type - concept - enum - enumerator + :concept:`TParamTemplate` + :enum:`TParamTemplate` + :enumerator:`TParamTemplate` .. function:: void FunctionParams(int FunctionParam) diff --git a/tests/roots/test-domain-py-xref-warning/conf.py b/tests/roots/test-domain-py-xref-warning/conf.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/roots/test-domain-py-xref-warning/conf.py diff --git a/tests/roots/test-domain-py-xref-warning/index.rst b/tests/roots/test-domain-py-xref-warning/index.rst new file mode 100644 index 000000000..6f2cab795 --- /dev/null +++ b/tests/roots/test-domain-py-xref-warning/index.rst @@ -0,0 +1,7 @@ +test-domain-py-xref-warning +=========================== + +.. _existing-label: + +:ref:`no-label` +:ref:`existing-label` diff --git a/tests/roots/test-domain-py/abbr.rst b/tests/roots/test-domain-py/abbr.rst new file mode 100644 index 000000000..67f11578b --- /dev/null +++ b/tests/roots/test-domain-py/abbr.rst @@ -0,0 +1,10 @@ +abbrev +====== + +.. currentmodule:: module_a.submodule + +* normal: :py:meth:`module_a.submodule.ModTopLevel.mod_child_1` +* relative: :py:meth:`.ModTopLevel.mod_child_1` +* short name: :py:meth:`~module_a.submodule.ModTopLevel.mod_child_1` +* relative + short name: :py:meth:`~.ModTopLevel.mod_child_1` +* short name + relative: :py:meth:`~.ModTopLevel.mod_child_1` diff --git a/tests/roots/test-ext-autodoc/autodoc_dummy_module.py b/tests/roots/test-ext-autodoc/autodoc_dummy_module.py index 5cc427ea4..1e9ed19dc 100644 --- a/tests/roots/test-ext-autodoc/autodoc_dummy_module.py +++ b/tests/roots/test-ext-autodoc/autodoc_dummy_module.py @@ -1,4 +1,4 @@ -from dummy import * # NOQA +from dummy import * # NOQA def test(): diff --git a/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py b/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py new file mode 100644 index 000000000..aa7eb99a6 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py @@ -0,0 +1,8 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from io import StringIO + + +class Foo: + attr1: "StringIO" diff --git a/tests/roots/test-ext-autodoc/target/__init__.py b/tests/roots/test-ext-autodoc/target/__init__.py index b6684ee85..e49f9a141 100644 --- a/tests/roots/test-ext-autodoc/target/__init__.py +++ b/tests/roots/test-ext-autodoc/target/__init__.py @@ -3,7 +3,6 @@ from io import StringIO from sphinx.util import save_traceback # NOQA - __all__ = ['Class'] #: documentation for the integer diff --git a/tests/roots/test-ext-autodoc/target/annotations.py b/tests/roots/test-ext-autodoc/target/annotations.py new file mode 100644 index 000000000..ef600e2af --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/annotations.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +from typing import overload + +myint = int + +#: docstring +variable: myint + +#: docstring +variable2 = None # type: myint + + +def sum(x: myint, y: myint) -> myint: + """docstring""" + return x + y + + +@overload +def mult(x: myint, y: myint) -> myint: + ... + + +@overload +def mult(x: float, y: float) -> float: + ... + + +def mult(x, y): + """docstring""" + return x, y + + +class Foo: + """docstring""" + + #: docstring + attr1: myint + + def __init__(self): + self.attr2: myint = None #: docstring diff --git a/tests/roots/test-ext-autodoc/target/cached_property.py b/tests/roots/test-ext-autodoc/target/cached_property.py new file mode 100644 index 000000000..63ec09f8e --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/cached_property.py @@ -0,0 +1,7 @@ +from functools import cached_property + + +class Foo: + @cached_property + def prop(self) -> int: + return 1 diff --git a/tests/roots/test-ext-autodoc/target/classes.py b/tests/roots/test-ext-autodoc/target/classes.py index dc471a6f3..a3b4c6477 100644 --- a/tests/roots/test-ext-autodoc/target/classes.py +++ b/tests/roots/test-ext-autodoc/target/classes.py @@ -1,3 +1,7 @@ +from inspect import Parameter, Signature +from typing import List, Union + + class Foo: pass @@ -10,3 +14,19 @@ class Bar: class Baz: def __new__(cls, x, y): pass + + +class Qux: + __signature__ = Signature(parameters=[Parameter('foo', Parameter.POSITIONAL_OR_KEYWORD), + Parameter('bar', Parameter.POSITIONAL_OR_KEYWORD)]) + + def __init__(self, x, y): + pass + + +class Quux(List[Union[int, float]]): + """A subclass of List[Union[int, float]]""" + pass + + +Alias = Foo diff --git a/tests/roots/test-ext-autodoc/target/decorator.py b/tests/roots/test-ext-autodoc/target/decorator.py index 61398b324..faad3fff9 100644 --- a/tests/roots/test-ext-autodoc/target/decorator.py +++ b/tests/roots/test-ext-autodoc/target/decorator.py @@ -29,3 +29,25 @@ class Bar: @deco1 def meth(self, name=None, age=None): pass + + +class Baz: + @deco1 + def __init__(self, name=None, age=None): + pass + + +class Qux: + @deco1 + def __new__(self, name=None, age=None): + pass + + +class _Metaclass(type): + @deco1 + def __call__(self, name=None, age=None): + pass + + +class Quux(metaclass=_Metaclass): + pass diff --git a/tests/roots/test-ext-autodoc/target/empty_all.py b/tests/roots/test-ext-autodoc/target/empty_all.py new file mode 100644 index 000000000..c094cff70 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/empty_all.py @@ -0,0 +1,16 @@ +""" +docsting of empty_all module. +""" +__all__ = [] + + +def foo(): + """docstring""" + + +def bar(): + """docstring""" + + +def baz(): + """docstring""" diff --git a/tests/roots/test-ext-autodoc/target/enum.py b/tests/roots/test-ext-autodoc/target/enums.py index c69455fb7..c69455fb7 100644 --- a/tests/roots/test-ext-autodoc/target/enum.py +++ b/tests/roots/test-ext-autodoc/target/enums.py diff --git a/tests/roots/test-ext-autodoc/target/generic_class.py b/tests/roots/test-ext-autodoc/target/generic_class.py new file mode 100644 index 000000000..e6ff38abc --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/generic_class.py @@ -0,0 +1,11 @@ +from typing import Generic, TypeVar + +T = TypeVar('T') + + +# Test that typing.Generic's __new__ method does not mask our class' +# __init__ signature. +class A(Generic[T]): + """docstring for A""" + def __init__(self, a, b=None): + pass diff --git a/tests/roots/test-ext-autodoc/target/genericalias.py b/tests/roots/test-ext-autodoc/target/genericalias.py index 78b68cd63..9909efca1 100644 --- a/tests/roots/test-ext-autodoc/target/genericalias.py +++ b/tests/roots/test-ext-autodoc/target/genericalias.py @@ -1,6 +1,11 @@ -from typing import List, Callable +from typing import Callable, List #: A list of int T = List[int] C = Callable[[int], None] # a generic alias not having a doccomment + + +class Class: + #: A list of int + T = List[int] diff --git a/tests/roots/test-ext-autodoc/target/hide_value.py b/tests/roots/test-ext-autodoc/target/hide_value.py new file mode 100644 index 000000000..1d53aabe9 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/hide_value.py @@ -0,0 +1,19 @@ +#: docstring +#: +#: :meta hide-value: +SENTINEL1 = object() + +#: :meta hide-value: +SENTINEL2 = object() + + +class Foo: + """docstring""" + + #: docstring + #: + #: :meta hide-value: + SENTINEL1 = object() + + #: :meta hide-value: + SENTINEL2 = object() diff --git a/tests/roots/test-ext-autodoc/target/instance_variable.py b/tests/roots/test-ext-autodoc/target/instance_variable.py new file mode 100644 index 000000000..ae86d1edb --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/instance_variable.py @@ -0,0 +1,10 @@ +class Foo: + def __init__(self): + self.attr1 = None #: docstring foo + self.attr2 = None #: docstring foo + + +class Bar(Foo): + def __init__(self): + self.attr2 = None #: docstring bar + self.attr3 = None #: docstring bar diff --git a/tests/roots/test-ext-autodoc/target/name_conflict/__init__.py b/tests/roots/test-ext-autodoc/target/name_conflict/__init__.py new file mode 100644 index 000000000..0a6f49653 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/name_conflict/__init__.py @@ -0,0 +1,6 @@ +from .foo import bar + + +class foo: + """docstring of target.name_conflict::foo.""" + pass diff --git a/tests/roots/test-ext-autodoc/target/name_conflict/foo.py b/tests/roots/test-ext-autodoc/target/name_conflict/foo.py new file mode 100644 index 000000000..bb83ca0d4 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/name_conflict/foo.py @@ -0,0 +1,2 @@ +class bar: + """docstring of target.name_conflict.foo::bar.""" diff --git a/tests/roots/test-ext-autodoc/target/name_mangling.py b/tests/roots/test-ext-autodoc/target/name_mangling.py new file mode 100644 index 000000000..269b51d93 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/name_mangling.py @@ -0,0 +1,11 @@ +class Foo: + #: name of Foo + __name = None + __age = None + + +class Bar(Foo): + __address = None + + #: a member having mangled-like name + _Baz__email = None diff --git a/tests/roots/test-ext-autodoc/target/need_mocks.py b/tests/roots/test-ext-autodoc/target/need_mocks.py index b8a661581..bc227f246 100644 --- a/tests/roots/test-ext-autodoc/target/need_mocks.py +++ b/tests/roots/test-ext-autodoc/target/need_mocks.py @@ -1,12 +1,12 @@ -import missing_module # NOQA -import missing_package1.missing_module1 # NOQA -from missing_module import missing_name # NOQA -from missing_package2 import missing_module2 # NOQA -from missing_package3.missing_module3 import missing_name # NOQA +import missing_module # NOQA +import missing_package1.missing_module1 # NOQA +from missing_module import missing_name # NOQA +from missing_package2 import missing_module2 # NOQA +from missing_package3.missing_module3 import missing_name # NOQA -import sphinx.missing_module4 # NOQA -from sphinx.missing_module4 import missing_name2 # NOQA +import sphinx.missing_module4 # NOQA +from sphinx.missing_module4 import missing_name2 # NOQA @missing_name @@ -28,4 +28,9 @@ class TestAutodoc(object): return None +class Inherited(missing_module.Class): + """docstring""" + pass + + sphinx.missing_module4.missing_function(len(missing_name2)) diff --git a/tests/roots/test-ext-autodoc/target/overload.py b/tests/roots/test-ext-autodoc/target/overload.py new file mode 100644 index 000000000..1b395ee5b --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/overload.py @@ -0,0 +1,88 @@ +from typing import Any, overload + + +@overload +def sum(x: int, y: int = 0) -> int: + ... + + +@overload +def sum(x: "float", y: "float" = 0.0) -> "float": + ... + + +@overload +def sum(x: str, y: str = ...) -> str: + ... + + +def sum(x, y=None): + """docstring""" + return x + y + + +class Math: + """docstring""" + + @overload + def sum(self, x: int, y: int = 0) -> int: + ... + + @overload + def sum(self, x: "float", y: "float" = 0.0) -> "float": + ... + + @overload + def sum(self, x: str, y: str = ...) -> str: + ... + + def sum(self, x, y=None): + """docstring""" + return x + y + + +class Foo: + """docstring""" + + @overload + def __new__(cls, x: int, y: int) -> "Foo": + ... + + @overload + def __new__(cls, x: "str", y: "str") -> "Foo": + ... + + def __new__(cls, x, y): + pass + + +class Bar: + """docstring""" + + @overload + def __init__(cls, x: int, y: int) -> None: + ... + + @overload + def __init__(cls, x: "str", y: "str") -> "None": + ... + + def __init__(cls, x, y): + pass + + +class Meta(type): + @overload + def __call__(cls, x: int, y: int) -> Any: + ... + + @overload + def __call__(cls, x: "str", y: "str") -> "Any": + ... + + def __call__(cls, x, y): + pass + + +class Baz(metaclass=Meta): + """docstring""" diff --git a/tests/roots/test-ext-autodoc/target/overload2.py b/tests/roots/test-ext-autodoc/target/overload2.py new file mode 100644 index 000000000..e901f791b --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/overload2.py @@ -0,0 +1,5 @@ +from target.overload import Bar + + +class Baz(Bar): + pass diff --git a/tests/roots/test-ext-autodoc/target/private.py b/tests/roots/test-ext-autodoc/target/private.py index a39ce085e..02d174863 100644 --- a/tests/roots/test-ext-autodoc/target/private.py +++ b/tests/roots/test-ext-autodoc/target/private.py @@ -9,3 +9,7 @@ def _public_function(name): :meta public: """ + + +PRIVATE_CONSTANT = None #: :meta private: +_PUBLIC_CONSTANT = None #: :meta public: diff --git a/tests/roots/test-ext-autodoc/target/singledispatch.py b/tests/roots/test-ext-autodoc/target/singledispatch.py index 33dcae43a..3fa81dcae 100644 --- a/tests/roots/test-ext-autodoc/target/singledispatch.py +++ b/tests/roots/test-ext-autodoc/target/singledispatch.py @@ -1,5 +1,5 @@ -from functools import singledispatch import inspect +from functools import singledispatch def assign_signature(func): diff --git a/tests/roots/test-ext-autodoc/target/slots.py b/tests/roots/test-ext-autodoc/target/slots.py index 44e750320..32822fd38 100644 --- a/tests/roots/test-ext-autodoc/target/slots.py +++ b/tests/roots/test-ext-autodoc/target/slots.py @@ -1,11 +1,21 @@ class Foo: + """docstring""" + __slots__ = ['attr'] class Bar: + """docstring""" + __slots__ = {'attr1': 'docstring of attr1', 'attr2': 'docstring of attr2', 'attr3': None} def __init__(self): self.attr2 = None #: docstring of instance attr2 + + +class Baz: + """docstring""" + + __slots__ = 'attr' diff --git a/tests/roots/test-ext-autodoc/target/typed_vars.py b/tests/roots/test-ext-autodoc/target/typed_vars.py index 65302fa44..f909b80f1 100644 --- a/tests/roots/test-ext-autodoc/target/typed_vars.py +++ b/tests/roots/test-ext-autodoc/target/typed_vars.py @@ -25,3 +25,10 @@ class Class: self.attr5: int #: attr5 self.attr6 = 0 # type: int """attr6""" + + +class Derived(Class): + attr7: int + + +Alias = Derived diff --git a/tests/roots/test-ext-autodoc/target/typehints.py b/tests/roots/test-ext-autodoc/target/typehints.py index 1a70eca67..2c9039650 100644 --- a/tests/roots/test-ext-autodoc/target/typehints.py +++ b/tests/roots/test-ext-autodoc/target/typehints.py @@ -1,4 +1,4 @@ -from typing import Tuple, Union +from typing import Any, Tuple, Union def incr(a: int, b: int = 1) -> int: @@ -11,7 +11,7 @@ def decr(a, b = 1): class Math: - def __init__(self, s: str, o: object = None) -> None: + def __init__(self, s: str, o: Any = None) -> None: pass def incr(self, a: int, b: int = 1) -> int: diff --git a/tests/roots/test-ext-autodoc/target/typevar.py b/tests/roots/test-ext-autodoc/target/typevar.py new file mode 100644 index 000000000..864fea20c --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/typevar.py @@ -0,0 +1,26 @@ +from typing import NewType, TypeVar + +#: T1 +T1 = TypeVar("T1") + +T2 = TypeVar("T2") # A TypeVar not having doc comment + +#: T3 +T3 = TypeVar("T3", int, str) + +#: T4 +T4 = TypeVar("T4", covariant=True) + +#: T5 +T5 = TypeVar("T5", contravariant=True) + +#: T6 +T6 = NewType("T6", int) + + +class Class: + #: T1 + T1 = TypeVar("T1") + + #: T6 + T6 = NewType("T6", int) diff --git a/tests/roots/test-ext-autodoc/target/wrappedfunction.py b/tests/roots/test-ext-autodoc/target/wrappedfunction.py index ea872f086..0bd2d2069 100644 --- a/tests/roots/test-ext-autodoc/target/wrappedfunction.py +++ b/tests/roots/test-ext-autodoc/target/wrappedfunction.py @@ -1,8 +1,15 @@ -# for py32 or above +from contextlib import contextmanager from functools import lru_cache +from typing import Generator @lru_cache(maxsize=None) def slow_function(message, timeout): """This function is slow.""" print(message) + + +@contextmanager +def feeling_good(x: int, y: int) -> Generator: + """You'll feel better in this context!""" + yield diff --git a/tests/roots/test-ext-autosummary-filename-map/autosummary_dummy_module.py b/tests/roots/test-ext-autosummary-filename-map/autosummary_dummy_module.py new file mode 100644 index 000000000..1f57eeb25 --- /dev/null +++ b/tests/roots/test-ext-autosummary-filename-map/autosummary_dummy_module.py @@ -0,0 +1,21 @@ +from os import path # NOQA +from typing import Union + + +class Foo: + class Bar: + pass + + def __init__(self): + pass + + def bar(self): + pass + + @property + def baz(self): + pass + + +def bar(x: Union[int, str], y: int = 1) -> None: + pass diff --git a/tests/roots/test-ext-autosummary-filename-map/conf.py b/tests/roots/test-ext-autosummary-filename-map/conf.py new file mode 100644 index 000000000..17e2fa445 --- /dev/null +++ b/tests/roots/test-ext-autosummary-filename-map/conf.py @@ -0,0 +1,11 @@ +import os +import sys + +sys.path.insert(0, os.path.abspath('.')) + +extensions = ['sphinx.ext.autosummary'] +autosummary_generate = True +autosummary_filename_map = { + "autosummary_dummy_module": "module_mangled", + "autosummary_dummy_module.bar": "bar" +} diff --git a/tests/roots/test-ext-autosummary-filename-map/index.rst b/tests/roots/test-ext-autosummary-filename-map/index.rst new file mode 100644 index 000000000..57d902b6a --- /dev/null +++ b/tests/roots/test-ext-autosummary-filename-map/index.rst @@ -0,0 +1,9 @@ + +.. autosummary:: + :toctree: generated + :caption: An autosummary + + autosummary_dummy_module + autosummary_dummy_module.Foo + autosummary_dummy_module.Foo.bar + autosummary_dummy_module.bar diff --git a/tests/roots/test-ext-autosummary-imported_members/conf.py b/tests/roots/test-ext-autosummary-imported_members/conf.py index 4cfff02dc..77af668ab 100644 --- a/tests/roots/test-ext-autosummary-imported_members/conf.py +++ b/tests/roots/test-ext-autosummary-imported_members/conf.py @@ -1,5 +1,6 @@ import os import sys + sys.path.insert(0, os.path.abspath('.')) extensions = ['sphinx.ext.autosummary'] diff --git a/tests/roots/test-ext-autosummary-mock_imports/conf.py b/tests/roots/test-ext-autosummary-mock_imports/conf.py index 1097e3c04..121f81459 100644 --- a/tests/roots/test-ext-autosummary-mock_imports/conf.py +++ b/tests/roots/test-ext-autosummary-mock_imports/conf.py @@ -1,5 +1,6 @@ import os import sys + sys.path.insert(0, os.path.abspath('.')) extensions = ['sphinx.ext.autosummary'] diff --git a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py index 85981a0f8..ca3475459 100644 --- a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py +++ b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py @@ -1,13 +1,22 @@ from os import path # NOQA from typing import Union +#: module variable +CONSTANT1 = None +CONSTANT2 = None + class Foo: + #: class variable + CONSTANT3 = None + CONSTANT4 = None + class Bar: pass def __init__(self): - pass + #: docstring + self.value = 1 def bar(self): pass diff --git a/tests/roots/test-ext-autosummary/index.rst b/tests/roots/test-ext-autosummary/index.rst index 9f657bb73..904c5fdcb 100644 --- a/tests/roots/test-ext-autosummary/index.rst +++ b/tests/roots/test-ext-autosummary/index.rst @@ -10,6 +10,7 @@ autosummary_dummy_module autosummary_dummy_module.Foo autosummary_dummy_module.Foo.Bar + autosummary_dummy_module.Foo.value autosummary_dummy_module.bar autosummary_dummy_module.qux autosummary_importfail diff --git a/tests/roots/test-ext-doctest-skipif/conf.py b/tests/roots/test-ext-doctest-skipif/conf.py index dfbc06f05..c863dbc01 100644 --- a/tests/roots/test-ext-doctest-skipif/conf.py +++ b/tests/roots/test-ext-doctest-skipif/conf.py @@ -6,7 +6,7 @@ source_suffix = '.txt' exclude_patterns = ['_build'] doctest_global_setup = ''' -from test_ext_doctest import record +from tests.test_ext_doctest import record record('doctest_global_setup', 'body', True) ''' diff --git a/tests/roots/test-ext-doctest/doctest.txt b/tests/roots/test-ext-doctest/doctest.txt index e45bc2721..04780cfbb 100644 --- a/tests/roots/test-ext-doctest/doctest.txt +++ b/tests/roots/test-ext-doctest/doctest.txt @@ -139,7 +139,7 @@ Special directives .. testcleanup:: * - import test_ext_doctest + from tests import test_ext_doctest test_ext_doctest.cleanup_call() non-ASCII result diff --git a/tests/roots/test-ext-math/index.rst b/tests/roots/test-ext-math/index.rst index 4237b73ff..221284aeb 100644 --- a/tests/roots/test-ext-math/index.rst +++ b/tests/roots/test-ext-math/index.rst @@ -6,6 +6,7 @@ Test Math math page + nomath .. math:: a^2+b^2=c^2 diff --git a/tests/roots/test-ext-math/nomath.rst b/tests/roots/test-ext-math/nomath.rst new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/roots/test-ext-math/nomath.rst diff --git a/tests/roots/test-ext-viewcode-find/not_a_package/__init__.py b/tests/roots/test-ext-viewcode-find/not_a_package/__init__.py index 8efc933b8..f79ec81f5 100644 --- a/tests/roots/test-ext-viewcode-find/not_a_package/__init__.py +++ b/tests/roots/test-ext-viewcode-find/not_a_package/__init__.py @@ -1 +1 @@ -from .submodule import func1, Class1 # NOQA +from .submodule import Class1, func1 # NOQA diff --git a/tests/roots/test-ext-viewcode/spam/__init__.py b/tests/roots/test-ext-viewcode/spam/__init__.py index 2d5ca8239..c438f6050 100644 --- a/tests/roots/test-ext-viewcode/spam/__init__.py +++ b/tests/roots/test-ext-viewcode/spam/__init__.py @@ -1,2 +1,2 @@ -from .mod1 import func1, Class1 # NOQA -from .mod2 import func2, Class2 # NOQA +from .mod1 import Class1, func1 # NOQA +from .mod2 import Class2, func2 # NOQA diff --git a/tests/roots/test-ext-viewcode/spam/mod3.py b/tests/roots/test-ext-viewcode/spam/mod3.py index f7b6afbe0..812c9b586 100644 --- a/tests/roots/test-ext-viewcode/spam/mod3.py +++ b/tests/roots/test-ext-viewcode/spam/mod3.py @@ -1,2 +1,3 @@ from spam.mod1 import Class3 + __all__ = ('Class3',) diff --git a/tests/roots/test-highlight_options/conf.py b/tests/roots/test-highlight_options/conf.py new file mode 100644 index 000000000..90997d444 --- /dev/null +++ b/tests/roots/test-highlight_options/conf.py @@ -0,0 +1,4 @@ +highlight_options = { + 'default': {'default_option': True}, + 'python': {'python_option': True} +} diff --git a/tests/roots/test-highlight_options/index.rst b/tests/roots/test-highlight_options/index.rst new file mode 100644 index 000000000..389041ace --- /dev/null +++ b/tests/roots/test-highlight_options/index.rst @@ -0,0 +1,14 @@ +test-highlight_options +====================== + +.. code-block:: + + blah blah blah + +.. code-block:: python + + blah blah blah + +.. code-block:: java + + blah blah blah diff --git a/tests/roots/test-html_assets/conf.py b/tests/roots/test-html_assets/conf.py index ec53011c2..7f94bbbce 100644 --- a/tests/roots/test-html_assets/conf.py +++ b/tests/roots/test-html_assets/conf.py @@ -4,7 +4,9 @@ version = '1.4.4' html_static_path = ['static', 'subdir'] html_extra_path = ['extra', 'subdir'] html_css_files = ['css/style.css', - ('https://example.com/custom.css', {'title': 'title', 'media': 'print'})] + ('https://example.com/custom.css', + {'title': 'title', 'media': 'print', 'priority': 400})] html_js_files = ['js/custom.js', - ('https://example.com/script.js', {'async': 'async'})] + ('https://example.com/script.js', + {'async': 'async', 'priority': 400})] exclude_patterns = ['**/_build', '**/.htpasswd'] diff --git a/tests/roots/test-intl/role_xref.txt b/tests/roots/test-intl/role_xref.txt index 875af4667..2919b5c7f 100644 --- a/tests/roots/test-intl/role_xref.txt +++ b/tests/roots/test-intl/role_xref.txt @@ -14,7 +14,7 @@ same type links link to :term:`Some term` and :term:`Some other term`. -link to :ref:`i18n-role-xref` and :ref:`same-type-links`. +link to :ref:`i18n-role-xref`, :ref:`same-type-links` and :ref:`label <same-type-links>`. link to :doc:`index` and :doc:`glossary_terms`. diff --git a/tests/roots/test-intl/xx/LC_MESSAGES/role_xref.po b/tests/roots/test-intl/xx/LC_MESSAGES/role_xref.po index 81ee22c6e..96d821fdb 100644 --- a/tests/roots/test-intl/xx/LC_MESSAGES/role_xref.po +++ b/tests/roots/test-intl/xx/LC_MESSAGES/role_xref.po @@ -28,8 +28,8 @@ msgstr "SAME TYPE LINKS" msgid "link to :term:`Some term` and :term:`Some other term`." msgstr "LINK TO :term:`SOME OTHER NEW TERM` AND :term:`SOME NEW TERM`." -msgid "link to :ref:`i18n-role-xref` and :ref:`same-type-links`." -msgstr "LINK TO :ref:`same-type-links` AND :ref:`i18n-role-xref`." +msgid "link to :ref:`i18n-role-xref`, :ref:`same-type-links` and :ref:`label <same-type-links>`." +msgstr "LINK TO :ref:`LABEL <i18n-role-xref>` AND :ref:`same-type-links` AND :ref:`same-type-links`." msgid "link to :doc:`index` and :doc:`glossary_terms`." msgstr "LINK TO :doc:`glossary_terms` AND :doc:`index`." diff --git a/tests/roots/test-intl/xx/LC_MESSAGES/toctree.po b/tests/roots/test-intl/xx/LC_MESSAGES/toctree.po index 8ca1dc52c..62cccdfc1 100644 --- a/tests/roots/test-intl/xx/LC_MESSAGES/toctree.po +++ b/tests/roots/test-intl/xx/LC_MESSAGES/toctree.po @@ -1,5 +1,5 @@ # SOME DESCRIPTIVE TITLE. -# Copyright (C) +# Copyright (C) # This file is distributed under the same license as the Sphinx intl <Tests> package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # diff --git a/tests/roots/test-latex-labels/index.rst b/tests/roots/test-latex-labels/index.rst index 781db5a01..f3c421750 100644 --- a/tests/roots/test-latex-labels/index.rst +++ b/tests/roots/test-latex-labels/index.rst @@ -69,4 +69,4 @@ subsubsection otherdoc -* Embeded standalone hyperlink reference(refs: #5948): `subsection <section1_>`_. +* Embedded standalone hyperlink reference(refs: #5948): `subsection <section1_>`_. diff --git a/tests/roots/test-linkcheck-localserver-anchor/conf.py b/tests/roots/test-linkcheck-localserver-anchor/conf.py new file mode 100644 index 000000000..2ba1f85e8 --- /dev/null +++ b/tests/roots/test-linkcheck-localserver-anchor/conf.py @@ -0,0 +1,2 @@ +exclude_patterns = ['_build'] +linkcheck_anchors = True diff --git a/tests/roots/test-linkcheck-localserver-anchor/index.rst b/tests/roots/test-linkcheck-localserver-anchor/index.rst new file mode 100644 index 000000000..807fe964b --- /dev/null +++ b/tests/roots/test-linkcheck-localserver-anchor/index.rst @@ -0,0 +1 @@ +`local server <http://localhost:7777/#anchor>`_ diff --git a/tests/roots/test-linkcheck-localserver-https/conf.py b/tests/roots/test-linkcheck-localserver-https/conf.py new file mode 100644 index 000000000..a45d22e28 --- /dev/null +++ b/tests/roots/test-linkcheck-localserver-https/conf.py @@ -0,0 +1 @@ +exclude_patterns = ['_build'] diff --git a/tests/roots/test-linkcheck-localserver-https/index.rst b/tests/roots/test-linkcheck-localserver-https/index.rst new file mode 100644 index 000000000..fea598359 --- /dev/null +++ b/tests/roots/test-linkcheck-localserver-https/index.rst @@ -0,0 +1 @@ +`HTTPS server <https://localhost:7777/>`_ diff --git a/tests/roots/test-linkcheck-localserver/conf.py b/tests/roots/test-linkcheck-localserver/conf.py new file mode 100644 index 000000000..a45d22e28 --- /dev/null +++ b/tests/roots/test-linkcheck-localserver/conf.py @@ -0,0 +1 @@ +exclude_patterns = ['_build'] diff --git a/tests/roots/test-linkcheck-localserver/index.rst b/tests/roots/test-linkcheck-localserver/index.rst new file mode 100644 index 000000000..c617e942f --- /dev/null +++ b/tests/roots/test-linkcheck-localserver/index.rst @@ -0,0 +1 @@ +`local server <http://localhost:7777/>`_ diff --git a/tests/roots/test-linkcheck/links.txt b/tests/roots/test-linkcheck/links.txt index fa8f11e4c..90759ee63 100644 --- a/tests/roots/test-linkcheck/links.txt +++ b/tests/roots/test-linkcheck/links.txt @@ -11,6 +11,8 @@ Some additional anchors to exercise ignore code * `Example Bar invalid <https://www.google.com/#top>`_ * `Example anchor invalid <http://www.sphinx-doc.org/en/1.7/intro.html#does-not-exist>`_ * `Complete nonsense <https://localhost:7777/doesnotexist>`_ +* `Example valid local file <conf.py>`_ +* `Example invalid local file <path/to/notfound>`_ .. image:: https://www.google.com/image.png .. figure:: https://www.google.com/image2.png diff --git a/tests/roots/test-numbered-circular/conf.py b/tests/roots/test-numbered-circular/conf.py index 027d21cda..a45d22e28 100644 --- a/tests/roots/test-numbered-circular/conf.py +++ b/tests/roots/test-numbered-circular/conf.py @@ -1 +1 @@ -exclude_patterns = ['_build']
+exclude_patterns = ['_build'] diff --git a/tests/roots/test-prolog/conf.py b/tests/roots/test-prolog/conf.py index e5ce87151..f6be09c5e 100644 --- a/tests/roots/test-prolog/conf.py +++ b/tests/roots/test-prolog/conf.py @@ -1,5 +1,6 @@ import os import sys + sys.path.insert(0, os.path.abspath('.')) diff --git a/tests/roots/test-pycode-egg/src/setup.py b/tests/roots/test-pycode-egg/src/setup.py index 6ad4986e4..1dfb1de29 100644 --- a/tests/roots/test-pycode-egg/src/setup.py +++ b/tests/roots/test-pycode-egg/src/setup.py @@ -1,5 +1,4 @@ from setuptools import setup - setup(name='sample', py_modules=['sample']) diff --git a/tests/roots/test-reST-code-block/conf.py b/tests/roots/test-reST-code-block/conf.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/roots/test-reST-code-block/conf.py diff --git a/tests/roots/test-reST-code-block/index.rst b/tests/roots/test-reST-code-block/index.rst new file mode 100644 index 000000000..a7c7df03a --- /dev/null +++ b/tests/roots/test-reST-code-block/index.rst @@ -0,0 +1,7 @@ +.. code-block:: + :linenos: + + def hello(name) + print("hello", name) + + hello("Sphinx") diff --git a/tests/roots/test-root/autodoc_target.py b/tests/roots/test-root/autodoc_target.py index a1540d90a..a49ffc1ff 100644 --- a/tests/roots/test-root/autodoc_target.py +++ b/tests/roots/test-root/autodoc_target.py @@ -1,7 +1,6 @@ import enum from io import StringIO - __all__ = ['Class'] #: documentation for the integer diff --git a/tests/roots/test-root/conf.py b/tests/roots/test-root/conf.py index b3cc12ae0..34cafa767 100644 --- a/tests/roots/test-root/conf.py +++ b/tests/roots/test-root/conf.py @@ -6,7 +6,6 @@ from docutils.parsers.rst import Directive from sphinx import addnodes - sys.path.append(os.path.abspath('.')) extensions = ['sphinx.ext.autodoc', @@ -32,8 +31,6 @@ pygments_style = 'sphinx' show_authors = True numfig = True -rst_epilog = '.. |subst| replace:: global substitution' - html_sidebars = {'**': ['localtoc.html', 'relations.html', 'sourcelink.html', 'customsb.html', 'searchbox.html'], 'index': ['contentssb.html', 'localtoc.html', 'globaltoc.html']} diff --git a/tests/roots/test-root/index.txt b/tests/roots/test-root/index.txt index 27f90f357..e39c958b3 100644 --- a/tests/roots/test-root/index.txt +++ b/tests/roots/test-root/index.txt @@ -32,14 +32,11 @@ Contents: Latest reference <http://sphinx-doc.org/latest/> Python <http://python.org/> - self - Indices and tables ================== * :ref:`genindex` * :ref:`modindex` -* :ref:`search` References ========== diff --git a/tests/roots/test-root/markup.txt b/tests/roots/test-root/markup.txt index e6adef55e..7cd3e95ea 100644 --- a/tests/roots/test-root/markup.txt +++ b/tests/roots/test-root/markup.txt @@ -22,7 +22,9 @@ Meta markup Generic reST ------------ -A |subst| (the definition is in rst_epilog). +A |subst|! + +.. |subst| replace:: global substitution .. highlight:: none diff --git a/tests/roots/test-root/objects.txt b/tests/roots/test-root/objects.txt index f713e076c..adb090a44 100644 --- a/tests/roots/test-root/objects.txt +++ b/tests/roots/test-root/objects.txt @@ -180,7 +180,9 @@ Others .. option:: arg -Link to :option:`perl +p`, :option:`--ObjC++`, :option:`--plugin.option`, :option:`create-auth-token` and :option:`arg` +.. option:: -j[=N] + +Link to :option:`perl +p`, :option:`--ObjC++`, :option:`--plugin.option`, :option:`create-auth-token`, :option:`arg` and :option:`-j` .. program:: hg diff --git a/tests/roots/test-theming/MANIFEST.in b/tests/roots/test-theming/MANIFEST.in index 0e977e756..0ace41cb7 100644 --- a/tests/roots/test-theming/MANIFEST.in +++ b/tests/roots/test-theming/MANIFEST.in @@ -1,2 +1,2 @@ -recursive-include test_theme *.conf
-
+recursive-include test_theme *.conf + diff --git a/tests/roots/test-theming/conf.py b/tests/roots/test-theming/conf.py index 062b9cf83..0db7cf035 100644 --- a/tests/roots/test-theming/conf.py +++ b/tests/roots/test-theming/conf.py @@ -1,3 +1,3 @@ -html_theme = 'test-theme'
-html_theme_path = ['.', 'test_theme']
-exclude_patterns = ['_build']
+html_theme = 'test-theme' +html_theme_path = ['.', 'test_theme'] +exclude_patterns = ['_build'] diff --git a/tests/roots/test-theming/index.rst b/tests/roots/test-theming/index.rst index 18a9a4e2f..214dcd7eb 100644 --- a/tests/roots/test-theming/index.rst +++ b/tests/roots/test-theming/index.rst @@ -1,5 +1,5 @@ -=======
-Theming
-=======
-
-
+======= +Theming +======= + + diff --git a/tests/roots/test-theming/setup.py b/tests/roots/test-theming/setup.py index e62007f36..7b504e807 100644 --- a/tests/roots/test-theming/setup.py +++ b/tests/roots/test-theming/setup.py @@ -1,11 +1,11 @@ -from setuptools import setup, find_packages
-
-setup(
- name='test-theme',
- packages=find_packages(),
- include_package_data=True,
- entry_points="""
- [sphinx_themes]
- path = test_theme:get_path
- """,
-)
+from setuptools import find_packages, setup + +setup( + name='test-theme', + packages=find_packages(), + include_package_data=True, + entry_points=""" + [sphinx_themes] + path = test_theme:get_path + """, +) diff --git a/tests/roots/test-theming/test_theme/__init__.py b/tests/roots/test-theming/test_theme/__init__.py index 398408c5d..13bdc4b2c 100644 --- a/tests/roots/test-theming/test_theme/__init__.py +++ b/tests/roots/test-theming/test_theme/__init__.py @@ -1,5 +1,5 @@ -import os
-
-
-def get_path():
- return os.path.dirname(os.path.abspath(__file__))
+import os + + +def get_path(): + return os.path.dirname(os.path.abspath(__file__)) diff --git a/tests/roots/test-toctree/index.rst b/tests/roots/test-toctree/index.rst index dc7fd2e4a..adf1b84dd 100644 --- a/tests/roots/test-toctree/index.rst +++ b/tests/roots/test-toctree/index.rst @@ -16,6 +16,7 @@ Contents: foo bar http://sphinx-doc.org/ + self .. only:: html diff --git a/tests/roots/test-trim_doctest_flags/index.rst b/tests/roots/test-trim_doctest_flags/index.rst index 63ce234cd..d63251a5a 100644 --- a/tests/roots/test-trim_doctest_flags/index.rst +++ b/tests/roots/test-trim_doctest_flags/index.rst @@ -22,7 +22,19 @@ test-trim_doctest_flags >>> datetime.date.now() # doctest: +QUX datetime.date(2008, 1, 1) -.. doctest_block:: +.. doctest:: >>> datetime.date.now() # doctest: +QUUX datetime.date(2008, 1, 1) + +.. doctest:: + :trim-doctest-flags: + + >>> datetime.date.now() # doctest: +CORGE + datetime.date(2008, 1, 1) + +.. doctest:: + :no-trim-doctest-flags: + + >>> datetime.date.now() # doctest: +GRAULT + datetime.date(2008, 1, 1) diff --git a/tests/roots/test-warnings/conf.py b/tests/roots/test-warnings/conf.py index 9d12e2d79..25b8aba07 100644 --- a/tests/roots/test-warnings/conf.py +++ b/tests/roots/test-warnings/conf.py @@ -1,5 +1,6 @@ import os import sys + sys.path.append(os.path.abspath('.')) extensions = ['sphinx.ext.autodoc'] diff --git a/tests/test_api_translator.py b/tests/test_api_translator.py index 47895a675..fddcd9d65 100644 --- a/tests/test_api_translator.py +++ b/tests/test_api_translator.py @@ -4,7 +4,7 @@ Test the Sphinx API for translator. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_application.py b/tests/test_application.py index a089a4bc0..94ddd04cf 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -4,7 +4,7 @@ Test the Sphinx class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_build.py b/tests/test_build.py index 9dcf78165..62de3ea5f 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -4,7 +4,7 @@ Test all builders. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -36,7 +36,11 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir): if not srcdir.exists(): (rootdir / 'test-root').copytree(srcdir) except UnicodeEncodeError: + # Now Python 3.7+ follows PEP-540 and uses utf-8 encoding for filesystem by default. + # So this error handling will be no longer used (after dropping python 3.6 support). srcdir = basedir / 'all' + if not srcdir.exists(): + (rootdir / 'test-root').copytree(srcdir) else: # add a doc with a non-ASCII file name to the source dir (srcdir / (test_name + '.txt')).write_text(dedent(""" diff --git a/tests/test_build_changes.py b/tests/test_build_changes.py index 3aedd03f5..c6cbd497d 100644 --- a/tests/test_build_changes.py +++ b/tests/test_build_changes.py @@ -1,11 +1,10 @@ -# -*- coding: utf-8 -*- """ test_build_changes ~~~~~~~~~~~~~~~~~~ Test the ChangesBuilder class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_build_dirhtml.py b/tests/test_build_dirhtml.py index e89e6888d..086b8426b 100644 --- a/tests/test_build_dirhtml.py +++ b/tests/test_build_dirhtml.py @@ -4,7 +4,7 @@ Test dirhtml builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_build_epub.py b/tests/test_build_epub.py index fc4b5329a..982f4c1b9 100644 --- a/tests/test_build_epub.py +++ b/tests/test_build_epub.py @@ -4,13 +4,13 @@ Test the HTML builder and check output against XPath. - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import subprocess -from subprocess import CalledProcessError, PIPE +from subprocess import PIPE, CalledProcessError from xml.etree import ElementTree import pytest @@ -391,6 +391,6 @@ def test_run_epubcheck(app): subprocess.run(['java', '-jar', epubcheck, app.outdir / 'SphinxTests.epub'], stdout=PIPE, stderr=PIPE, check=True) except CalledProcessError as exc: - print(exc.stdout) - print(exc.stderr) + print(exc.stdout.decode('utf-8')) + print(exc.stderr.decode('utf-8')) assert False, 'epubcheck exited with return code %s' % exc.returncode diff --git a/tests/test_build_gettext.py b/tests/test_build_gettext.py index 1c86b8daa..92ec384b5 100644 --- a/tests/test_build_gettext.py +++ b/tests/test_build_gettext.py @@ -4,7 +4,7 @@ Test the build process with gettext builder with the test root. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,7 +12,7 @@ import gettext import os import re import subprocess -from subprocess import CalledProcessError, PIPE +from subprocess import PIPE, CalledProcessError import pytest @@ -174,3 +174,21 @@ def test_gettext_template_msgid_order_in_sphinxpot(app): 'msgid "This is Template 2\\.".*'), result, flags=re.S) + + +@pytest.mark.sphinx( + 'gettext', srcdir='root-gettext', + confoverrides={'gettext_compact': 'documentation'}) +def test_build_single_pot(app): + app.builder.build_all() + + assert (app.outdir / 'documentation.pot').isfile() + + result = (app.outdir / 'documentation.pot').read_text() + assert re.search( + ('msgid "Todo".*' + 'msgid "Like footnotes.".*' + 'msgid "The minute.".*' + 'msgid "Generated section".*'), + result, + flags=re.S) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index b3406b74c..9abfa19aa 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -4,14 +4,17 @@ Test the HTML builder and check output against XPath. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import re -from itertools import cycle, chain +from distutils.version import LooseVersion +from itertools import chain, cycle +from unittest.mock import ANY, call, patch +import pygments import pytest from html5lib import HTMLParser @@ -21,7 +24,6 @@ from sphinx.testing.util import strip_escseq from sphinx.util import docutils, md5 from sphinx.util.inventory import InventoryFile - ENV_WARNINGS = """\ %(root)s/autodoc_fodder.py:docstring of autodoc_fodder.MarkupError:\\d+: \ WARNING: Explicit markup ends without a blank line; unexpected unindent. @@ -256,7 +258,7 @@ def test_html4_output(app, status, warning): (".//pre/strong", 'try_stmt'), (".//pre/a[@href='#grammar-token-try1_stmt']/code/span", 'try1_stmt'), # tests for ``only`` directive - (".//p", 'A global substitution.'), + (".//p", 'A global substitution!'), (".//p", 'In HTML.'), (".//p", 'In both.'), (".//p", 'Always present'), @@ -331,6 +333,8 @@ def test_html4_output(app, status, warning): 'create-auth-token'), (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-arg']/code/span", 'arg'), + (".//a[@class='reference internal'][@href='#cmdoption-perl-j']/code/span", + '-j'), (".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span", 'hg'), (".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span", @@ -355,7 +359,6 @@ def test_html4_output(app, status, warning): "[@class='reference external']", ''), (".//li/p/a[@href='genindex.html']/span", 'Index'), (".//li/p/a[@href='py-modindex.html']/span", 'Module Index'), - (".//li/p/a[@href='search.html']/span", 'Search Page'), # custom sidebar only for contents (".//h4", 'Contents sidebar'), # custom JavaScript @@ -418,6 +421,11 @@ def test_html5_output(app, cached_etree_parse, fname, expect): check_xpath(cached_etree_parse(app.outdir / fname), fname, *expect) +@pytest.mark.sphinx('html', parallel=2) +def test_html_parallel(app): + app.build() + + @pytest.mark.skipif(docutils.__version_info__ < (0, 13), reason='docutils-0.13 or above is required') @pytest.mark.sphinx('html') @@ -653,7 +661,7 @@ def test_numfig_without_numbered_toctree_warn(app, warning): warnings = warning.getvalue() assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' not in warnings - assert 'index.rst:55: WARNING: no number is assigned for section: index' in warnings + assert 'index.rst:55: WARNING: Failed to create a cross reference. Any number is not assigned: index' in warnings assert 'index.rst:56: WARNING: invalid numfig_format: invalid' in warnings assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' in warnings @@ -761,7 +769,7 @@ def test_numfig_with_numbered_toctree_warn(app, warning): app.build() warnings = warning.getvalue() assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' not in warnings - assert 'index.rst:55: WARNING: no number is assigned for section: index' in warnings + assert 'index.rst:55: WARNING: Failed to create a cross reference. Any number is not assigned: index' in warnings assert 'index.rst:56: WARNING: invalid numfig_format: invalid' in warnings assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' in warnings @@ -866,7 +874,7 @@ def test_numfig_with_prefix_warn(app, warning): app.build() warnings = warning.getvalue() assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' not in warnings - assert 'index.rst:55: WARNING: no number is assigned for section: index' in warnings + assert 'index.rst:55: WARNING: Failed to create a cross reference. Any number is not assigned: index' in warnings assert 'index.rst:56: WARNING: invalid numfig_format: invalid' in warnings assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' in warnings @@ -972,7 +980,7 @@ def test_numfig_with_secnum_depth_warn(app, warning): app.build() warnings = warning.getvalue() assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' not in warnings - assert 'index.rst:55: WARNING: no number is assigned for section: index' in warnings + assert 'index.rst:55: WARNING: Failed to create a cross reference. Any number is not assigned: index' in warnings assert 'index.rst:56: WARNING: invalid numfig_format: invalid' in warnings assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' in warnings @@ -1221,6 +1229,35 @@ def test_html_assets(app): '</script>' in content) +@pytest.mark.sphinx('html', testroot='html_assets') +def test_assets_order(app): + app.add_css_file('normal.css') + app.add_css_file('early.css', priority=100) + app.add_css_file('late.css', priority=750) + app.add_css_file('lazy.css', priority=900) + app.add_js_file('normal.js') + app.add_js_file('early.js', priority=100) + app.add_js_file('late.js', priority=750) + app.add_js_file('lazy.js', priority=900) + + app.builder.build_all() + content = (app.outdir / 'index.html').read_text() + + # css_files + expected = ['_static/pygments.css', '_static/alabaster.css', '_static/early.css', + 'https://example.com/custom.css', '_static/normal.css', '_static/late.css', + '_static/css/style.css', '_static/lazy.css'] + pattern = '.*'.join('href="%s"' % f for f in expected) + assert re.search(pattern, content, re.S) + + # js_files + expected = ['_static/early.js', '_static/jquery.js', '_static/underscore.js', + '_static/doctools.js', 'https://example.com/script.js', '_static/normal.js', + '_static/late.js', '_static/js/custom.js', '_static/lazy.js'] + pattern = '.*'.join('src="%s"' % f for f in expected) + assert re.search(pattern, content, re.S) + + @pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_copy_source': False}) def test_html_copy_source(app): app.builder.build_all() @@ -1573,3 +1610,78 @@ def test_html_scaled_image_link(app): assert re.search('\n<img alt="_images/img.png" class="no-scaled-link"' ' src="_images/img.png" style="[^"]+" />', context) + + +@pytest.mark.sphinx('html', testroot='reST-code-block', + confoverrides={'html_codeblock_linenos_style': 'table'}) +def test_html_codeblock_linenos_style_table(app): + app.build() + content = (app.outdir / 'index.html').read_text() + + assert '<div class="linenodiv"><pre>1\n2\n3\n4</pre></div>' in content + + +@pytest.mark.sphinx('html', testroot='reST-code-block', + confoverrides={'html_codeblock_linenos_style': 'inline'}) +def test_html_codeblock_linenos_style_inline(app): + app.build() + content = (app.outdir / 'index.html').read_text() + + pygments_version = tuple(LooseVersion(pygments.__version__).version) + if pygments_version > (2, 7): + assert '<span class="linenos">1</span>' in content + else: + assert '<span class="lineno">1 </span>' in content + + +@pytest.mark.sphinx('html', testroot='highlight_options') +def test_highlight_options(app): + subject = app.builder.highlighter + with patch.object(subject, 'highlight_block', wraps=subject.highlight_block) as highlight: + app.build() + + call_args = highlight.call_args_list + assert len(call_args) == 3 + assert call_args[0] == call(ANY, 'default', force=False, linenos=False, + location=ANY, opts={'default_option': True}) + assert call_args[1] == call(ANY, 'python', force=False, linenos=False, + location=ANY, opts={'python_option': True}) + assert call_args[2] == call(ANY, 'java', force=False, linenos=False, + location=ANY, opts={}) + + +@pytest.mark.sphinx('html', testroot='highlight_options', + confoverrides={'highlight_options': {'default_option': True}}) +def test_highlight_options_old(app): + subject = app.builder.highlighter + with patch.object(subject, 'highlight_block', wraps=subject.highlight_block) as highlight: + app.build() + + call_args = highlight.call_args_list + assert len(call_args) == 3 + assert call_args[0] == call(ANY, 'default', force=False, linenos=False, + location=ANY, opts={'default_option': True}) + assert call_args[1] == call(ANY, 'python', force=False, linenos=False, + location=ANY, opts={}) + assert call_args[2] == call(ANY, 'java', force=False, linenos=False, + location=ANY, opts={}) + + +@pytest.mark.sphinx('html', testroot='basic', + confoverrides={'html_permalinks': False}) +def test_html_permalink_disable(app): + app.build() + content = (app.outdir / 'index.html').read_text() + + assert '<h1>The basic Sphinx documentation for testing</h1>' in content + + +@pytest.mark.sphinx('html', testroot='basic', + confoverrides={'html_permalinks_icon': '<span>[PERMALINK]</span>'}) +def test_html_permalink_icon(app): + app.build() + content = (app.outdir / 'index.html').read_text() + + assert ('<h1>The basic Sphinx documentation for testing<a class="headerlink" ' + 'href="#the-basic-sphinx-documentation-for-testing" ' + 'title="Permalink to this headline"><span>[PERMALINK]</span></a></h1>' in content) diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index d3c491461..6f6041aea 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -4,7 +4,7 @@ Test the build process with LaTeX builder with the test root. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,19 +13,19 @@ import re import subprocess from itertools import product from shutil import copyfile -from subprocess import CalledProcessError, PIPE +from subprocess import PIPE, CalledProcessError import pytest -from test_build_html import ENV_WARNINGS from sphinx.builders.latex import default_latex_documents from sphinx.config import Config -from sphinx.errors import SphinxError, ThemeError +from sphinx.errors import SphinxError from sphinx.testing.util import strip_escseq from sphinx.util import docutils from sphinx.util.osutil import cd, ensuredir from sphinx.writers.latex import LaTeXTranslator +from .test_build_html import ENV_WARNINGS LATEX_ENGINES = ['pdflatex', 'lualatex', 'xelatex'] DOCCLASSES = ['howto', 'manual'] @@ -64,8 +64,8 @@ def compile_latex_document(app, filename='python.tex'): '-output-directory=%s' % app.config.latex_engine, filename] subprocess.run(args, stdout=PIPE, stderr=PIPE, check=True) - except OSError: # most likely the latex executable was not found - raise pytest.skip.Exception + except OSError as exc: # most likely the latex executable was not found + raise pytest.skip.Exception from exc except CalledProcessError as exc: print(exc.stdout) print(exc.stderr) @@ -764,7 +764,7 @@ def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning): assert ('\\caption{This is the figure caption with a footnote to ' '\\sphinxfootnotemark[7].}\\label{\\detokenize{index:id29}}\\end{figure}\n' '%\n\\begin{footnotetext}[7]\\sphinxAtStartFootnote\n' - 'Footnote in caption\n%\n\\end{footnotetext}')in result + 'Footnote in caption\n%\n\\end{footnotetext}') in result assert ('\\sphinxcaption{footnote \\sphinxfootnotemark[8] in ' 'caption of normal table}\\label{\\detokenize{index:id30}}') in result assert ('\\caption{footnote \\sphinxfootnotemark[9] ' @@ -1477,7 +1477,7 @@ def test_latex_labels(app, status, warning): r'\label{\detokenize{otherdoc:otherdoc}}' r'\label{\detokenize{otherdoc::doc}}' in result) - # Embeded standalone hyperlink reference (refs: #5948) + # Embedded standalone hyperlink reference (refs: #5948) assert result.count(r'\label{\detokenize{index:section1}}') == 1 @@ -1545,7 +1545,7 @@ def test_texescape_for_unicode_supported_engine(app, status, warning): assert 'superscript: ⁰, ¹' in result assert 'subscript: ₀, ₁' in result - + @pytest.mark.sphinx('latex', testroot='basic', confoverrides={'latex_elements': {'extrapackages': r'\usepackage{foo}'}}) def test_latex_elements_extrapackages(app, status, warning): diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index 54bde6b68..55a2bf233 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -4,18 +4,33 @@ Test the build process with manpage builder with the test root. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import http.server import json import re +import textwrap +import time +import wsgiref.handlers +from datetime import datetime +from typing import Dict from unittest import mock + import pytest +import requests + +from sphinx.builders.linkcheck import CheckExternalLinksBuilder, RateLimit +from sphinx.util.console import strip_colors + +from .utils import CERT_FILE, http_server, https_server + +ts_re = re.compile(r".*\[(?P<ts>.*)\].*") @pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True) -def test_defaults(app, status, warning): +def test_defaults(app): app.builder.build_all() assert (app.outdir / 'output.txt').exists() @@ -30,11 +45,13 @@ def test_defaults(app, status, warning): # images should fail assert "Not Found for url: https://www.google.com/image.png" in content assert "Not Found for url: https://www.google.com/image2.png" in content - assert len(content.splitlines()) == 5 + # looking for local file should fail + assert "[broken] path/to/notfound" in content + assert len(content.splitlines()) == 6 @pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True) -def test_defaults_json(app, status, warning): +def test_defaults_json(app): app.builder.build_all() assert (app.outdir / 'output.json').exists() @@ -47,11 +64,11 @@ def test_defaults_json(app, status, warning): "info"]: assert attr in row - assert len(content.splitlines()) == 8 - assert len(rows) == 8 + assert len(content.splitlines()) == 10 + assert len(rows) == 10 # the output order of the rows is not stable # due to possible variance in network latency - rowsby = {row["uri"]:row for row in rows} + rowsby = {row["uri"]: row for row in rows} assert rowsby["https://www.google.com#!bar"] == { 'filename': 'links.txt', 'lineno': 10, @@ -69,7 +86,7 @@ def test_defaults_json(app, status, warning): assert dnerow['uri'] == 'https://localhost:7777/doesnotexist' assert rowsby['https://www.google.com/image2.png'] == { 'filename': 'links.txt', - 'lineno': 16, + 'lineno': 18, 'status': 'broken', 'code': 0, 'uri': 'https://www.google.com/image2.png', @@ -92,9 +109,10 @@ def test_defaults_json(app, status, warning): 'https://localhost:7777/doesnotexist', 'http://www.sphinx-doc.org/en/1.7/intro.html#', 'https://www.google.com/image.png', - 'https://www.google.com/image2.png'] + 'https://www.google.com/image2.png', + 'path/to/notfound'] }) -def test_anchors_ignored(app, status, warning): +def test_anchors_ignored(app): app.builder.build_all() assert (app.outdir / 'output.txt').exists() @@ -104,23 +122,454 @@ def test_anchors_ignored(app, status, warning): assert not content +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-anchor', freshenv=True) +def test_raises_for_invalid_status(app): + class InternalServerErrorHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + self.send_error(500, "Internal Server Error") + + with http_server(InternalServerErrorHandler): + app.builder.build_all() + content = (app.outdir / 'output.txt').read_text() + assert content == ( + "index.rst:1: [broken] http://localhost:7777/#anchor: " + "500 Server Error: Internal Server Error " + "for url: http://localhost:7777/\n" + ) + + +class HeadersDumperHandler(http.server.BaseHTTPRequestHandler): + def do_HEAD(self): + self.do_GET() + + def do_GET(self): + self.send_response(200, "OK") + self.end_headers() + print(self.headers.as_string()) + + @pytest.mark.sphinx( - 'linkcheck', testroot='linkcheck', freshenv=True, + 'linkcheck', testroot='linkcheck-localserver', freshenv=True, confoverrides={'linkcheck_auth': [ - (r'.+google\.com/image.+', 'authinfo1'), - (r'.+google\.com.+', 'authinfo2'), - ] - }) -def test_auth(app, status, warning): - mock_req = mock.MagicMock() - mock_req.return_value = 'fake-response' - - with mock.patch.multiple('requests', get=mock_req, head=mock_req): - app.builder.build_all() - for c_args, c_kwargs in mock_req.call_args_list: - if 'google.com/image' in c_args[0]: - assert c_kwargs['auth'] == 'authinfo1' - elif 'google.com' in c_args[0]: - assert c_kwargs['auth'] == 'authinfo2' + (r'^$', ('no', 'match')), + (r'^http://localhost:7777/$', ('user1', 'password')), + (r'.*local.*', ('user2', 'hunter2')), + ]}) +def test_auth_header_uses_first_match(app, capsys): + with http_server(HeadersDumperHandler): + app.builder.build_all() + stdout, stderr = capsys.readouterr() + auth = requests.auth._basic_auth_str('user1', 'password') + assert "Authorization: %s\n" % auth in stdout + + +@pytest.mark.sphinx( + 'linkcheck', testroot='linkcheck-localserver', freshenv=True, + confoverrides={'linkcheck_auth': [(r'^$', ('user1', 'password'))]}) +def test_auth_header_no_match(app, capsys): + with http_server(HeadersDumperHandler): + app.builder.build_all() + stdout, stderr = capsys.readouterr() + assert "Authorization" not in stdout + + +@pytest.mark.sphinx( + 'linkcheck', testroot='linkcheck-localserver', freshenv=True, + confoverrides={'linkcheck_request_headers': { + "http://localhost:7777/": { + "Accept": "text/html", + }, + "*": { + "X-Secret": "open sesami", + } + }}) +def test_linkcheck_request_headers(app, capsys): + with http_server(HeadersDumperHandler): + app.builder.build_all() + + stdout, _stderr = capsys.readouterr() + assert "Accept: text/html\n" in stdout + assert "X-Secret" not in stdout + assert "sesami" not in stdout + + +@pytest.mark.sphinx( + 'linkcheck', testroot='linkcheck-localserver', freshenv=True, + confoverrides={'linkcheck_request_headers': { + "http://localhost:7777": {"Accept": "application/json"}, + "*": {"X-Secret": "open sesami"} + }}) +def test_linkcheck_request_headers_no_slash(app, capsys): + with http_server(HeadersDumperHandler): + app.builder.build_all() + + stdout, _stderr = capsys.readouterr() + assert "Accept: application/json\n" in stdout + assert "X-Secret" not in stdout + assert "sesami" not in stdout + + +@pytest.mark.sphinx( + 'linkcheck', testroot='linkcheck-localserver', freshenv=True, + confoverrides={'linkcheck_request_headers': { + "http://do.not.match.org": {"Accept": "application/json"}, + "*": {"X-Secret": "open sesami"} + }}) +def test_linkcheck_request_headers_default(app, capsys): + with http_server(HeadersDumperHandler): + app.builder.build_all() + + stdout, _stderr = capsys.readouterr() + assert "Accepts: application/json\n" not in stdout + assert "X-Secret: open sesami\n" in stdout + + +def make_redirect_handler(*, support_head): + class RedirectOnceHandler(http.server.BaseHTTPRequestHandler): + def do_HEAD(self): + if support_head: + self.do_GET() else: - assert not c_kwargs['auth'] + self.send_response(405, "Method Not Allowed") + self.end_headers() + + def do_GET(self): + if self.path == "/?redirected=1": + self.send_response(204, "No content") + else: + self.send_response(302, "Found") + self.send_header("Location", "http://localhost:7777/?redirected=1") + self.end_headers() + + def log_date_time_string(self): + """Strip date and time from logged messages for assertions.""" + return "" + + return RedirectOnceHandler + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) +def test_follows_redirects_on_HEAD(app, capsys): + with http_server(make_redirect_handler(support_head=True)): + app.builder.build_all() + stdout, stderr = capsys.readouterr() + content = (app.outdir / 'output.txt').read_text() + assert content == ( + "index.rst:1: [redirected with Found] " + "http://localhost:7777/ to http://localhost:7777/?redirected=1\n" + ) + assert stderr == textwrap.dedent( + """\ + 127.0.0.1 - - [] "HEAD / HTTP/1.1" 302 - + 127.0.0.1 - - [] "HEAD /?redirected=1 HTTP/1.1" 204 - + """ + ) + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) +def test_follows_redirects_on_GET(app, capsys): + with http_server(make_redirect_handler(support_head=False)): + app.builder.build_all() + stdout, stderr = capsys.readouterr() + content = (app.outdir / 'output.txt').read_text() + assert content == ( + "index.rst:1: [redirected with Found] " + "http://localhost:7777/ to http://localhost:7777/?redirected=1\n" + ) + assert stderr == textwrap.dedent( + """\ + 127.0.0.1 - - [] "HEAD / HTTP/1.1" 405 - + 127.0.0.1 - - [] "GET / HTTP/1.1" 302 - + 127.0.0.1 - - [] "GET /?redirected=1 HTTP/1.1" 204 - + """ + ) + + +class OKHandler(http.server.BaseHTTPRequestHandler): + def do_HEAD(self): + self.send_response(200, "OK") + self.end_headers() + + def do_GET(self): + self.do_HEAD() + self.wfile.write(b"ok\n") + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True) +def test_invalid_ssl(app): + # Link indicates SSL should be used (https) but the server does not handle it. + with http_server(OKHandler): + app.builder.build_all() + + with open(app.outdir / 'output.json') as fp: + content = json.load(fp) + assert content["status"] == "broken" + assert content["filename"] == "index.rst" + assert content["lineno"] == 1 + assert content["uri"] == "https://localhost:7777/" + assert "SSLError" in content["info"] + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True) +def test_connect_to_selfsigned_fails(app): + with https_server(OKHandler): + app.builder.build_all() + + with open(app.outdir / 'output.json') as fp: + content = json.load(fp) + assert content["status"] == "broken" + assert content["filename"] == "index.rst" + assert content["lineno"] == 1 + assert content["uri"] == "https://localhost:7777/" + assert "[SSL: CERTIFICATE_VERIFY_FAILED]" in content["info"] + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True) +def test_connect_to_selfsigned_with_tls_verify_false(app): + app.config.tls_verify = False + with https_server(OKHandler): + app.builder.build_all() + + with open(app.outdir / 'output.json') as fp: + content = json.load(fp) + assert content == { + "code": 0, + "status": "working", + "filename": "index.rst", + "lineno": 1, + "uri": "https://localhost:7777/", + "info": "", + } + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True) +def test_connect_to_selfsigned_with_tls_cacerts(app): + app.config.tls_cacerts = CERT_FILE + with https_server(OKHandler): + app.builder.build_all() + + with open(app.outdir / 'output.json') as fp: + content = json.load(fp) + assert content == { + "code": 0, + "status": "working", + "filename": "index.rst", + "lineno": 1, + "uri": "https://localhost:7777/", + "info": "", + } + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True) +def test_connect_to_selfsigned_with_requests_env_var(monkeypatch, app): + monkeypatch.setenv("REQUESTS_CA_BUNDLE", CERT_FILE) + with https_server(OKHandler): + app.builder.build_all() + + with open(app.outdir / 'output.json') as fp: + content = json.load(fp) + assert content == { + "code": 0, + "status": "working", + "filename": "index.rst", + "lineno": 1, + "uri": "https://localhost:7777/", + "info": "", + } + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True) +def test_connect_to_selfsigned_nonexistent_cert_file(app): + app.config.tls_cacerts = "does/not/exist" + with https_server(OKHandler): + app.builder.build_all() + + with open(app.outdir / 'output.json') as fp: + content = json.load(fp) + assert content == { + "code": 0, + "status": "broken", + "filename": "index.rst", + "lineno": 1, + "uri": "https://localhost:7777/", + "info": "Could not find a suitable TLS CA certificate bundle, invalid path: does/not/exist", + } + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) +def test_TooManyRedirects_on_HEAD(app): + class InfiniteRedirectOnHeadHandler(http.server.BaseHTTPRequestHandler): + def do_HEAD(self): + self.send_response(302, "Found") + self.send_header("Location", "http://localhost:7777/") + self.end_headers() + + def do_GET(self): + self.send_response(200, "OK") + self.end_headers() + self.wfile.write(b"ok\n") + + with http_server(InfiniteRedirectOnHeadHandler): + app.builder.build_all() + + with open(app.outdir / 'output.json') as fp: + content = json.load(fp) + assert content == { + "code": 0, + "status": "working", + "filename": "index.rst", + "lineno": 1, + "uri": "http://localhost:7777/", + "info": "", + } + + +def make_retry_after_handler(responses): + class RetryAfterHandler(http.server.BaseHTTPRequestHandler): + def do_HEAD(self): + status, retry_after = responses.pop(0) + self.send_response(status) + if retry_after: + self.send_header('Retry-After', retry_after) + self.end_headers() + + def log_date_time_string(self): + """Strip date and time from logged messages for assertions.""" + return "" + + return RetryAfterHandler + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) +def test_too_many_requests_retry_after_int_delay(app, capsys, status): + with http_server(make_retry_after_handler([(429, "0"), (200, None)])), \ + mock.patch("sphinx.builders.linkcheck.DEFAULT_DELAY", 0), \ + mock.patch("sphinx.builders.linkcheck.QUEUE_POLL_SECS", 0.01): + app.builder.build_all() + content = (app.outdir / 'output.json').read_text() + assert json.loads(content) == { + "filename": "index.rst", + "lineno": 1, + "status": "working", + "code": 0, + "uri": "http://localhost:7777/", + "info": "", + } + rate_limit_log = "-rate limited- http://localhost:7777/ | sleeping...\n" + assert rate_limit_log in strip_colors(status.getvalue()) + _stdout, stderr = capsys.readouterr() + assert stderr == textwrap.dedent( + """\ + 127.0.0.1 - - [] "HEAD / HTTP/1.1" 429 - + 127.0.0.1 - - [] "HEAD / HTTP/1.1" 200 - + """ + ) + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) +def test_too_many_requests_retry_after_HTTP_date(app, capsys): + now = datetime.now().timetuple() + retry_after = wsgiref.handlers.format_date_time(time.mktime(now)) + with http_server(make_retry_after_handler([(429, retry_after), (200, None)])): + app.builder.build_all() + content = (app.outdir / 'output.json').read_text() + assert json.loads(content) == { + "filename": "index.rst", + "lineno": 1, + "status": "working", + "code": 0, + "uri": "http://localhost:7777/", + "info": "", + } + _stdout, stderr = capsys.readouterr() + assert stderr == textwrap.dedent( + """\ + 127.0.0.1 - - [] "HEAD / HTTP/1.1" 429 - + 127.0.0.1 - - [] "HEAD / HTTP/1.1" 200 - + """ + ) + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) +def test_too_many_requests_retry_after_without_header(app, capsys): + with http_server(make_retry_after_handler([(429, None), (200, None)])),\ + mock.patch("sphinx.builders.linkcheck.DEFAULT_DELAY", 0): + app.builder.build_all() + content = (app.outdir / 'output.json').read_text() + assert json.loads(content) == { + "filename": "index.rst", + "lineno": 1, + "status": "working", + "code": 0, + "uri": "http://localhost:7777/", + "info": "", + } + _stdout, stderr = capsys.readouterr() + assert stderr == textwrap.dedent( + """\ + 127.0.0.1 - - [] "HEAD / HTTP/1.1" 429 - + 127.0.0.1 - - [] "HEAD / HTTP/1.1" 200 - + """ + ) + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) +def test_too_many_requests_user_timeout(app, capsys): + app.config.linkcheck_rate_limit_timeout = 0.0 + with http_server(make_retry_after_handler([(429, None)])): + app.builder.build_all() + content = (app.outdir / 'output.json').read_text() + assert json.loads(content) == { + "filename": "index.rst", + "lineno": 1, + "status": "broken", + "code": 0, + "uri": "http://localhost:7777/", + "info": "429 Client Error: Too Many Requests for url: http://localhost:7777/", + } + + +class FakeResponse: + headers = {} # type: Dict[str, str] + url = "http://localhost/" + + +def test_limit_rate_default_sleep(app): + checker = CheckExternalLinksBuilder(app) + checker.rate_limits = {} + with mock.patch('time.time', return_value=0.0): + next_check = checker.limit_rate(FakeResponse()) + assert next_check == 60.0 + + +def test_limit_rate_user_max_delay(app): + app.config.linkcheck_rate_limit_timeout = 0.0 + checker = CheckExternalLinksBuilder(app) + checker.rate_limits = {} + next_check = checker.limit_rate(FakeResponse()) + assert next_check is None + + +def test_limit_rate_doubles_previous_wait_time(app): + checker = CheckExternalLinksBuilder(app) + checker.rate_limits = {"localhost": RateLimit(60.0, 0.0)} + with mock.patch('time.time', return_value=0.0): + next_check = checker.limit_rate(FakeResponse()) + assert next_check == 120.0 + + +def test_limit_rate_clips_wait_time_to_max_time(app): + checker = CheckExternalLinksBuilder(app) + app.config.linkcheck_rate_limit_timeout = 90.0 + checker.rate_limits = {"localhost": RateLimit(60.0, 0.0)} + with mock.patch('time.time', return_value=0.0): + next_check = checker.limit_rate(FakeResponse()) + assert next_check == 90.0 + + +def test_limit_rate_bails_out_after_waiting_max_time(app): + checker = CheckExternalLinksBuilder(app) + app.config.linkcheck_rate_limit_timeout = 90.0 + checker.rate_limits = {"localhost": RateLimit(90.0, 0.0)} + next_check = checker.limit_rate(FakeResponse()) + assert next_check is None diff --git a/tests/test_build_manpage.py b/tests/test_build_manpage.py index c3c41a2ae..a017abc69 100644 --- a/tests/test_build_manpage.py +++ b/tests/test_build_manpage.py @@ -4,7 +4,7 @@ Test the build process with manpage builder with the test root. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -30,6 +30,13 @@ def test_all(app, status, warning): assert 'Footnotes' not in content +@pytest.mark.sphinx('man', testroot='basic', + confoverrides={'man_make_section_directory': True}) +def test_man_make_section_directory(app, status, warning): + app.build() + assert (app.outdir / '1' / 'python.1').exists() + + @pytest.mark.sphinx('man', testroot='directive-code') def test_captioned_code_block(app, status, warning): app.builder.build_all() diff --git a/tests/test_build_texinfo.py b/tests/test_build_texinfo.py index 378eaa192..546ccaabf 100644 --- a/tests/test_build_texinfo.py +++ b/tests/test_build_texinfo.py @@ -4,18 +4,17 @@ Test the build process with Texinfo builder with the test root. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import re import subprocess -from subprocess import CalledProcessError, PIPE +from subprocess import PIPE, CalledProcessError from unittest.mock import Mock import pytest -from test_build_html import ENV_WARNINGS from sphinx.builders.texinfo import default_texinfo_documents from sphinx.config import Config @@ -23,6 +22,7 @@ from sphinx.testing.util import strip_escseq from sphinx.util.docutils import new_document from sphinx.writers.texinfo import TexinfoTranslator +from .test_build_html import ENV_WARNINGS TEXINFO_WARNINGS = ENV_WARNINGS + """\ %(root)s/index.rst:\\d+: WARNING: unknown option: &option @@ -58,8 +58,8 @@ def test_texinfo(app, status, warning): try: args = ['makeinfo', '--no-split', 'sphinxtests.texi'] subprocess.run(args, stdout=PIPE, stderr=PIPE, cwd=app.outdir, check=True) - except OSError: - raise pytest.skip.Exception # most likely makeinfo was not found + except OSError as exc: + raise pytest.skip.Exception from exc # most likely makeinfo was not found except CalledProcessError as exc: print(exc.stdout) print(exc.stderr) diff --git a/tests/test_build_text.py b/tests/test_build_text.py index 8c00f5550..e3d8ff111 100644 --- a/tests/test_build_text.py +++ b/tests/test_build_text.py @@ -4,14 +4,14 @@ Test the build process with Text builder with the test root. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest from docutils.utils import column_width -from sphinx.writers.text import MAXWIDTH, Table, Cell +from sphinx.writers.text import MAXWIDTH, Cell, Table def with_text_app(*args, **kw): diff --git a/tests/test_builder.py b/tests/test_builder.py index 4a37db84d..ed3f8cdaa 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -4,7 +4,7 @@ Test the Builder class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest diff --git a/tests/test_catalogs.py b/tests/test_catalogs.py index e603a5812..986979fe2 100644 --- a/tests/test_catalogs.py +++ b/tests/test_catalogs.py @@ -4,7 +4,7 @@ Test the base build process. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import shutil diff --git a/tests/test_config.py b/tests/test_config.py index 552cbc90d..9a0b617d5 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -5,7 +5,7 @@ Test the sphinx.config.Config class and its handling in the Application class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,8 +14,8 @@ from unittest import mock import pytest import sphinx -from sphinx.config import Config, ENUM, check_confval_types -from sphinx.errors import ExtensionError, ConfigError, VersionRequirementError +from sphinx.config import ENUM, Config, check_confval_types +from sphinx.errors import ConfigError, ExtensionError, VersionRequirementError from sphinx.testing.path import path diff --git a/tests/test_correct_year.py b/tests/test_correct_year.py index 7dc3ea89d..6afcce2b5 100644 --- a/tests/test_correct_year.py +++ b/tests/test_correct_year.py @@ -4,7 +4,7 @@ Test copyright year adjustment - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest diff --git a/tests/test_directive_code.py b/tests/test_directive_code.py index eda331645..0ae11baf3 100644 --- a/tests/test_directive_code.py +++ b/tests/test_directive_code.py @@ -4,7 +4,7 @@ Test the code-block directive. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -250,6 +250,14 @@ def test_LiteralIncludeReader_dedent(literal_inc_path): " pass\n" "\n") + # dedent: None + options = {'lines': '9-11', 'dedent': None} + reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG) + content, lines = reader.read() + assert content == ("def baz():\n" + " pass\n" + "\n") + @pytest.mark.xfail(os.name != 'posix', reason="Not working on windows") def test_LiteralIncludeReader_tabwidth(testroot): diff --git a/tests/test_directive_only.py b/tests/test_directive_only.py index 3de22c71f..72cbc6bd7 100644 --- a/tests/test_directive_only.py +++ b/tests/test_directive_only.py @@ -4,7 +4,7 @@ Test the only directive with the test root. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_directive_other.py b/tests/test_directive_other.py index 52e4a937c..09877208c 100644 --- a/tests/test_directive_other.py +++ b/tests/test_directive_other.py @@ -4,7 +4,7 @@ Test the other directives. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_directive_patch.py b/tests/test_directive_patch.py index 8572ff672..7dc568b1d 100644 --- a/tests/test_directive_patch.py +++ b/tests/test_directive_patch.py @@ -4,7 +4,7 @@ Test the patched directives. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_docutilsconf.py b/tests/test_docutilsconf.py index 02a7fc62b..9f12fd004 100644 --- a/tests/test_docutilsconf.py +++ b/tests/test_docutilsconf.py @@ -4,7 +4,7 @@ Test docutils.conf support for several writers. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py index 10a20b9d1..2cfcf74fa 100644 --- a/tests/test_domain_c.py +++ b/tests/test_domain_c.py @@ -4,14 +4,19 @@ Tests the C Domain - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ + +import zlib +from xml.etree import ElementTree + import pytest from sphinx import addnodes -from sphinx.domains.c import DefinitionParser, DefinitionError -from sphinx.domains.c import _max_id, _id_prefix, Symbol +from sphinx.addnodes import desc +from sphinx.domains.c import DefinitionError, DefinitionParser, Symbol, _id_prefix, _max_id +from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node @@ -51,8 +56,8 @@ def _check(name, input, idDict, output, key, asTextOutput): print("Result: ", res) print("Expected: ", outputAst) raise DefinitionError("") - rootSymbol = Symbol(None, None, None, None) - symbol = rootSymbol.add_declaration(ast, docname="TestDoc") + rootSymbol = Symbol(None, None, None, None, None) + symbol = rootSymbol.add_declaration(ast, docname="TestDoc", line=42) parentNode = addnodes.desc() signode = addnodes.desc_signature(input, '') parentNode += signode @@ -73,12 +78,12 @@ def _check(name, input, idDict, output, key, asTextOutput): idExpected.append(idExpected[i - 1]) idActual = [None] for i in range(1, _max_id + 1): - #try: + # try: id = ast.get_id(version=i) assert id is not None idActual.append(id[len(_id_prefix[i]):]) - #except NoOldIdError: - # idActual.append(None) + # except NoOldIdError: + # idActual.append(None) res = [True] for i in range(1, _max_id + 1): @@ -92,7 +97,7 @@ def _check(name, input, idDict, output, key, asTextOutput): print("Error in id version %d." % i) print("result: %s" % idActual[i]) print("expected: %s" % idExpected[i]) - #print(rootSymbol.dump(0)) + # print(rootSymbol.dump(0)) raise DefinitionError("") @@ -104,7 +109,7 @@ def check(name, input, idDict, output=None, key=None, asTextOutput=None): if name != 'macro': # Second, check with semicolon _check(name, input + ' ;', idDict, output + ';', key, - asTextOutput + ';' if asTextOutput is not None else None) + asTextOutput + ';' if asTextOutput is not None else None) def test_expressions(): @@ -295,6 +300,10 @@ def test_macro_definitions(): check('macro', 'M(arg, ...)', {1: 'M'}) check('macro', 'M(arg1, arg2, ...)', {1: 'M'}) check('macro', 'M(arg1, arg2, arg3, ...)', {1: 'M'}) + # GNU extension + check('macro', 'M(arg1, arg2, arg3...)', {1: 'M'}) + with pytest.raises(DefinitionError): + check('macro', 'M(arg1, arg2..., arg3)', {1: 'M'}) def test_member_definitions(): @@ -416,7 +425,7 @@ def test_nested_name(): check('function', 'void f(.A.B a)', {1: "f"}) -def test_union_definitions(): +def test_struct_definitions(): check('struct', '{key}A', {1: 'A'}) @@ -469,12 +478,14 @@ def test_attributes(): check('member', '__attribute__(()) int f', {1: 'f'}) check('member', '__attribute__((a)) int f', {1: 'f'}) check('member', '__attribute__((a, b)) int f', {1: 'f'}) + check('member', '__attribute__((optimize(3))) int f', {1: 'f'}) + check('member', '__attribute__((format(printf, 1, 2))) int f', {1: 'f'}) # style: user-defined id check('member', 'id_attr int f', {1: 'f'}) # style: user-defined paren check('member', 'paren_attr() int f', {1: 'f'}) check('member', 'paren_attr(a) int f', {1: 'f'}) - check('member', 'paren_attr("") int f',{1: 'f'}) + check('member', 'paren_attr("") int f', {1: 'f'}) check('member', 'paren_attr(()[{}][]{}) int f', {1: 'f'}) with pytest.raises(DefinitionError): parse('member', 'paren_attr(() int f') @@ -490,17 +501,16 @@ def test_attributes(): parse('member', 'paren_attr({]}) int f') # position: decl specs - check('function', 'static inline __attribute__(()) void f()', - {1: 'f'}, + check('function', 'static inline __attribute__(()) void f()', {1: 'f'}, output='__attribute__(()) static inline void f()') - check('function', '[[attr1]] [[attr2]] void f()', - {1: 'f'}, - output='[[attr1]] [[attr2]] void f()') + check('function', '[[attr1]] [[attr2]] void f()', {1: 'f'}) # position: declarator check('member', 'int *[[attr]] i', {1: 'i'}) check('member', 'int *const [[attr]] volatile i', {1: 'i'}, output='int *[[attr]] volatile const i') check('member', 'int *[[attr]] *i', {1: 'i'}) + # position: parameters + check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f'}) # issue michaeljones/breathe#500 check('function', 'LIGHTGBM_C_EXPORT int LGBM_BoosterFree(int handle)', @@ -514,7 +524,7 @@ def test_attributes(): def filter_warnings(warning, file): - lines = warning.getvalue().split("\n"); + lines = warning.getvalue().split("\n") res = [l for l in lines if "domain-c" in l and "{}.rst".format(file) in l and "WARNING: document isn't included in any toctree" not in l] print("Filtered warnings for file '{}':".format(file)) @@ -523,6 +533,25 @@ def filter_warnings(warning, file): return res +def extract_role_links(app, filename): + t = (app.outdir / filename).read_text() + lis = [l for l in t.split('\n') if l.startswith("<li")] + entries = [] + for l in lis: + li = ElementTree.fromstring(l) + aList = list(li.iter('a')) + assert len(aList) == 1 + a = aList[0] + target = a.attrib['href'].lstrip('#') + title = a.attrib['title'] + assert len(a) == 1 + code = a[0] + assert code.tag == 'code' + text = ''.join(code.itertext()) + entries.append((target, title, text)) + return entries + + @pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True}) def test_build_domain_c(app, status, warning): app.builder.build_all() @@ -556,6 +585,34 @@ def test_build_domain_c_semicolon(app, status, warning): assert len(ws) == 0 +@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True}) +def test_build_function_param_target(app, warning): + # the anchor for function parameters should be the function + app.builder.build_all() + ws = filter_warnings(warning, "function_param_target") + assert len(ws) == 0 + entries = extract_role_links(app, "function_param_target.html") + assert entries == [ + ('c.f', 'i', 'i'), + ('c.f', 'f.i', 'f.i'), + ] + + +@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True}) +def test_build_ns_lookup(app, warning): + app.builder.build_all() + ws = filter_warnings(warning, "ns_lookup") + assert len(ws) == 0 + + +def _get_obj(app, queryName): + domain = app.env.get_domain('c') + for name, dispname, objectType, docname, anchor, prio in domain.get_objects(): + if name == queryName: + return (docname, anchor, objectType) + return (queryName, "not", "found") + + def test_cfunction(app): text = (".. c:function:: PyObject* " "PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)") @@ -563,8 +620,7 @@ def test_cfunction(app): assert_node(doctree[1], addnodes.desc, desctype="function", domain="c", objtype="function", noindex=False) - domain = app.env.get_domain('c') - entry = domain.objects.get('PyType_GenericAlloc') + entry = _get_obj(app, 'PyType_GenericAlloc') assert entry == ('index', 'c.PyType_GenericAlloc', 'function') @@ -574,8 +630,7 @@ def test_cmember(app): assert_node(doctree[1], addnodes.desc, desctype="member", domain="c", objtype="member", noindex=False) - domain = app.env.get_domain('c') - entry = domain.objects.get('PyTypeObject.tp_bases') + entry = _get_obj(app, 'PyTypeObject.tp_bases') assert entry == ('index', 'c.PyTypeObject.tp_bases', 'member') @@ -585,6 +640,64 @@ def test_cvar(app): assert_node(doctree[1], addnodes.desc, desctype="var", domain="c", objtype="var", noindex=False) - domain = app.env.get_domain('c') - entry = domain.objects.get('PyClass_Type') - assert entry == ('index', 'c.PyClass_Type', 'var') + entry = _get_obj(app, 'PyClass_Type') + assert entry == ('index', 'c.PyClass_Type', 'member') + + +def test_noindexentry(app): + text = (".. c:function:: void f()\n" + ".. c:function:: void g()\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C function)', 'c.f', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) + + +@pytest.mark.sphinx(testroot='domain-c-intersphinx', confoverrides={'nitpicky': True}) +def test_intersphinx(tempdir, app, status, warning): + origSource = """\ +.. c:member:: int _member +.. c:var:: int _var +.. c:function:: void _function() +.. c:macro:: _macro +.. c:struct:: _struct +.. c:union:: _union +.. c:enum:: _enum + + .. c:enumerator:: _enumerator + +.. c:type:: _type +.. c:function:: void _functionParam(int param) +""" # noqa + inv_file = tempdir / 'inventory' + inv_file.write_bytes(b'''\ +# Sphinx inventory version 2 +# Project: C Intersphinx Test +# Version: +# The remainder of this file is compressed using zlib. +''' + zlib.compress(b'''\ +_enum c:enum 1 index.html#c.$ - +_enum._enumerator c:enumerator 1 index.html#c.$ - +_enumerator c:enumerator 1 index.html#c._enum.$ - +_function c:function 1 index.html#c.$ - +_functionParam c:function 1 index.html#c.$ - +_functionParam.param c:functionParam 1 index.html#c._functionParam - +_macro c:macro 1 index.html#c.$ - +_member c:member 1 index.html#c.$ - +_struct c:struct 1 index.html#c.$ - +_type c:type 1 index.html#c.$ - +_union c:union 1 index.html#c.$ - +_var c:member 1 index.html#c.$ - +''')) # noqa + app.config.intersphinx_mapping = { + 'https://localhost/intersphinx/c/': inv_file, + } + app.config.intersphinx_cache_limit = 0 + # load the inventory and check if it's done correctly + normalize_intersphinx_mapping(app, app.config) + load_mappings(app) + + app.builder.build_all() + ws = filter_warnings(warning, "index") + assert len(ws) == 0 diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 961646131..690093f5c 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -4,18 +4,23 @@ Tests the C++ Domain - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re +import zlib import pytest import sphinx.domains.cpp as cppDomain from sphinx import addnodes -from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError -from sphinx.domains.cpp import Symbol, _max_id, _id_prefix +from sphinx.addnodes import desc +from sphinx.domains.cpp import (DefinitionError, DefinitionParser, NoOldIdError, Symbol, + _id_prefix, _max_id) +from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping +from sphinx.testing import restructuredtext +from sphinx.testing.util import assert_node from sphinx.util import docutils @@ -57,8 +62,8 @@ def _check(name, input, idDict, output, key, asTextOutput): print("Result: ", res) print("Expected: ", outputAst) raise DefinitionError("") - rootSymbol = Symbol(None, None, None, None, None, None) - symbol = rootSymbol.add_declaration(ast, docname="TestDoc") + rootSymbol = Symbol(None, None, None, None, None, None, None) + symbol = rootSymbol.add_declaration(ast, docname="TestDoc", line=42) parentNode = addnodes.desc() signode = addnodes.desc_signature(input, '') parentNode += signode @@ -179,9 +184,9 @@ def test_expressions(): expr = i + l + u exprCheck(expr, 'L' + expr + 'E') decimalFloats = ['5e42', '5e+42', '5e-42', - '5.', '5.e42', '5.e+42', '5.e-42', - '.5', '.5e42', '.5e+42', '.5e-42', - '5.0', '5.0e42', '5.0e+42', '5.0e-42'] + '5.', '5.e42', '5.e+42', '5.e-42', + '.5', '.5e42', '.5e+42', '.5e-42', + '5.0', '5.0e42', '5.0e+42', '5.0e-42'] hexFloats = ['ApF', 'Ap+F', 'Ap-F', 'A.', 'A.pF', 'A.p+F', 'A.p-F', '.A', '.ApF', '.Ap+F', '.Ap-F', @@ -422,9 +427,9 @@ def test_member_definitions(): check('member', 'int b : 8 = 42', {1: 'b__i', 2: '1b'}) check('member', 'int b : 8{42}', {1: 'b__i', 2: '1b'}) # TODO: enable once the ternary operator is supported - #check('member', 'int b : true ? 8 : a = 42', {1: 'b__i', 2: '1b'}) + # check('member', 'int b : true ? 8 : a = 42', {1: 'b__i', 2: '1b'}) # TODO: enable once the ternary operator is supported - #check('member', 'int b : (true ? 8 : a) = 42', {1: 'b__i', 2: '1b'}) + # check('member', 'int b : (true ? 8 : a) = 42', {1: 'b__i', 2: '1b'}) check('member', 'int b : 1 || new int{0}', {1: 'b__i', 2: '1b'}) @@ -534,8 +539,8 @@ def test_function_definitions(): check('function', 'int foo(const A*...)', {1: "foo__ACPDp", 2: "3fooDpPK1A"}) check('function', 'int foo(const int A::*... a)', {2: "3fooDpM1AKi"}) check('function', 'int foo(const int A::*...)', {2: "3fooDpM1AKi"}) - #check('function', 'int foo(int (*a)(A)...)', {1: "foo__ACRDp", 2: "3fooDpPK1A"}) - #check('function', 'int foo(int (*)(A)...)', {1: "foo__ACRDp", 2: "3fooDpPK1A"}) + # check('function', 'int foo(int (*a)(A)...)', {1: "foo__ACRDp", 2: "3fooDpPK1A"}) + # check('function', 'int foo(int (*)(A)...)', {1: "foo__ACRDp", 2: "3fooDpPK1A"}) check('function', 'virtual void f()', {1: "f", 2: "1fv"}) # test for ::nestedName, from issue 1738 check("function", "result(int val, ::std::error_category const &cat)", @@ -704,7 +709,6 @@ def test_class_definitions(): check('class', 'template<class T> {key}has_var<T, std::void_t<decltype(&T::var)>>', {2: 'I0E7has_varI1TNSt6void_tIDTadN1T3varEEEEE'}) - check('class', 'template<typename ...Ts> {key}T<int (*)(Ts)...>', {2: 'IDpE1TIJPFi2TsEEE'}) check('class', 'template<int... Is> {key}T<(Is)...>', @@ -757,9 +761,11 @@ def test_templates(): check('class', "template<typename T = Test> {key}A", {2: "I0E1A"}) check('class', "template<template<typename> typename T> {key}A", {2: "II0E0E1A"}) + check('class', "template<template<typename> class T> {key}A", {2: "II0E0E1A"}) check('class', "template<template<typename> typename> {key}A", {2: "II0E0E1A"}) check('class', "template<template<typename> typename ...T> {key}A", {2: "II0EDpE1A"}) check('class', "template<template<typename> typename...> {key}A", {2: "II0EDpE1A"}) + check('class', "template<typename T, template<typename> typename...> {key}A", {2: "I0I0EDpE1A"}) check('class', "template<int> {key}A", {2: "I_iE1A"}) check('class', "template<int T> {key}A", {2: "I_iE1A"}) @@ -767,6 +773,16 @@ def test_templates(): check('class', "template<int T = 42> {key}A", {2: "I_iE1A"}) check('class', "template<int = 42> {key}A", {2: "I_iE1A"}) + check('class', "template<typename A<B>::C> {key}A", {2: "I_N1AI1BE1CEE1A"}) + check('class', "template<typename A<B>::C = 42> {key}A", {2: "I_N1AI1BE1CEE1A"}) + # from #7944 + check('function', "template<typename T, " + "typename std::enable_if<!has_overloaded_addressof<T>::value, bool>::type = false" + "> constexpr T *static_addressof(T &ref)", + {2: "I0_NSt9enable_ifIX!has_overloaded_addressof<T>::valueEbE4typeEE16static_addressofR1T", + 3: "I0_NSt9enable_ifIXntN24has_overloaded_addressofI1TE5valueEEbE4typeEE16static_addressofR1T", + 4: "I0_NSt9enable_ifIXntN24has_overloaded_addressofI1TE5valueEEbE4typeEE16static_addressofP1TR1T"}) + check('class', "template<> {key}A<NS::B<>>", {2: "IE1AIN2NS1BIEEE"}) # from #2058 @@ -897,6 +913,8 @@ def test_attributes(): check('member', '__attribute__(()) int f', {1: 'f__i', 2: '1f'}) check('member', '__attribute__((a)) int f', {1: 'f__i', 2: '1f'}) check('member', '__attribute__((a, b)) int f', {1: 'f__i', 2: '1f'}) + check('member', '__attribute__((optimize(3))) int f', {1: 'f__i', 2: '1f'}) + check('member', '__attribute__((format(printf, 1, 2))) int f', {1: 'f__i', 2: '1f'}) # style: user-defined id check('member', 'id_attr int f', {1: 'f__i', 2: '1f'}) # style: user-defined paren @@ -921,15 +939,15 @@ def test_attributes(): check('function', 'static inline __attribute__(()) void f()', {1: 'f', 2: '1fv'}, output='__attribute__(()) static inline void f()') - check('function', '[[attr1]] [[attr2]] void f()', - {1: 'f', 2: '1fv'}, - output='[[attr1]] [[attr2]] void f()') + check('function', '[[attr1]] [[attr2]] void f()', {1: 'f', 2: '1fv'}) # position: declarator check('member', 'int *[[attr]] i', {1: 'i__iP', 2: '1i'}) check('member', 'int *const [[attr]] volatile i', {1: 'i__iPVC', 2: '1i'}, output='int *[[attr]] volatile const i') check('member', 'int &[[attr]] i', {1: 'i__iR', 2: '1i'}) check('member', 'int *[[attr]] *i', {1: 'i__iPP', 2: '1i'}) + # position: parameters and qualifiers + check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f', 2: '1fv'}) def test_xref_parsing(): @@ -984,7 +1002,7 @@ def test_build_domain_cpp_warn_template_param_qualified_name(app, status, warnin @pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True}) -def test_build_domain_cpp_backslash_ok(app, status, warning): +def test_build_domain_cpp_backslash_ok_true(app, status, warning): app.builder.build_all() ws = filter_warnings(warning, "backslash") assert len(ws) == 0 @@ -999,7 +1017,7 @@ def test_build_domain_cpp_semicolon(app, status, warning): @pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True, 'strip_signature_backslash': True}) -def test_build_domain_cpp_backslash_ok(app, status, warning): +def test_build_domain_cpp_backslash_ok_false(app, status, warning): app.builder.build_all() ws = filter_warnings(warning, "backslash") assert len(ws) == 1 @@ -1033,8 +1051,8 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning): ('concept', ['concept']), ('enum', ['type', 'enum']), ('enumerator', ['enumerator']), - ('tParam', ['class', 'struct', 'union', 'func', 'member', 'var', 'type', 'concept', 'enum', 'enumerator', 'functionParam']), ('functionParam', ['member', 'var']), + ('templateParam', ['class', 'struct', 'union', 'member', 'var', 'type']), ] warn = [] for targetType, roles in ok: @@ -1042,6 +1060,9 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning): for r in allRoles: if r not in roles: warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType)) + if targetType == 'templateParam': + warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType)) + warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType)) warn = list(sorted(warn)) for w in ws: assert "targets a" in w @@ -1209,3 +1230,91 @@ not found in `{test}` assert any_role.classes == cpp_any_role.classes, expect assert any_role.classes == expr_role.content_classes['a'], expect assert any_role.classes == texpr_role.content_classes['a'], expect + + +def test_noindexentry(app): + text = (".. cpp:function:: void f()\n" + ".. cpp:function:: void g()\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C++ function)', '_CPPv41fv', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) + + +def test_mix_decl_duplicate(app, warning): + # Issue 8270 + text = (".. cpp:struct:: A\n" + ".. cpp:function:: void A()\n" + ".. cpp:struct:: A\n") + restructuredtext.parse(app, text) + ws = warning.getvalue().split("\n") + assert len(ws) == 5 + assert "index.rst:2: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[0] + assert "Declaration is '.. cpp:function:: void A()'." in ws[1] + assert "index.rst:3: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[2] + assert "Declaration is '.. cpp:struct:: A'." in ws[3] + assert ws[4] == "" + + +@pytest.mark.sphinx(testroot='domain-cpp-intersphinx', confoverrides={'nitpicky': True}) +def test_intersphinx(tempdir, app, status, warning): + origSource = """\ +.. cpp:class:: _class +.. cpp:struct:: _struct +.. cpp:union:: _union +.. cpp:function:: void _function() +.. cpp:member:: int _member +.. cpp:var:: int _var +.. cpp:type:: _type +.. cpp:concept:: template<typename T> _concept +.. cpp:enum:: _enum + + .. cpp:enumerator:: _enumerator + +.. cpp:enum-struct:: _enumStruct + + .. cpp:enumerator:: _scopedEnumerator + +.. cpp:enum-class:: _enumClass +.. cpp:function:: void _functionParam(int param) +.. cpp:function:: template<typename TParam> void _templateParam() +""" # noqa + inv_file = tempdir / 'inventory' + inv_file.write_bytes(b'''\ +# Sphinx inventory version 2 +# Project: C Intersphinx Test +# Version: +# The remainder of this file is compressed using zlib. +''' + zlib.compress(b'''\ +_class cpp:class 1 index.html#_CPPv46$ - +_concept cpp:concept 1 index.html#_CPPv4I0E8$ - +_concept::T cpp:templateParam 1 index.html#_CPPv4I0E8_concept - +_enum cpp:enum 1 index.html#_CPPv45$ - +_enum::_enumerator cpp:enumerator 1 index.html#_CPPv4N5_enum11_enumeratorE - +_enumClass cpp:enum 1 index.html#_CPPv410$ - +_enumStruct cpp:enum 1 index.html#_CPPv411$ - +_enumStruct::_scopedEnumerator cpp:enumerator 1 index.html#_CPPv4N11_enumStruct17_scopedEnumeratorE - +_enumerator cpp:enumerator 1 index.html#_CPPv4N5_enum11_enumeratorE - +_function cpp:function 1 index.html#_CPPv49_functionv - +_functionParam cpp:function 1 index.html#_CPPv414_functionParami - +_functionParam::param cpp:functionParam 1 index.html#_CPPv414_functionParami - +_member cpp:member 1 index.html#_CPPv47$ - +_struct cpp:class 1 index.html#_CPPv47$ - +_templateParam cpp:function 1 index.html#_CPPv4I0E14_templateParamvv - +_templateParam::TParam cpp:templateParam 1 index.html#_CPPv4I0E14_templateParamvv - +_type cpp:type 1 index.html#_CPPv45$ - +_union cpp:union 1 index.html#_CPPv46$ - +_var cpp:member 1 index.html#_CPPv44$ - +''')) # noqa + app.config.intersphinx_mapping = { + 'https://localhost/intersphinx/cpp/': inv_file, + } + app.config.intersphinx_cache_limit = 0 + # load the inventory and check if it's done correctly + normalize_intersphinx_mapping(app, app.config) + load_mappings(app) + + app.builder.build_all() + ws = filter_warnings(warning, "index") + assert len(ws) == 0 diff --git a/tests/test_domain_js.py b/tests/test_domain_js.py index 189f22e5b..1fb865d4b 100644 --- a/tests/test_domain_js.py +++ b/tests/test_domain_js.py @@ -4,7 +4,7 @@ Tests the JavaScript Domain - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,10 +14,8 @@ import pytest from docutils import nodes from sphinx import addnodes -from sphinx.addnodes import ( - desc, desc_annotation, desc_content, desc_name, - desc_parameter, desc_parameterlist, desc_signature -) +from sphinx.addnodes import (desc, desc_annotation, desc_content, desc_name, desc_parameter, + desc_parameterlist, desc_signature) from sphinx.domains.javascript import JavaScriptDomain from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node @@ -218,3 +216,13 @@ def test_js_data(app): assert_node(doctree[0], addnodes.index, entries=[("single", "name (global variable or constant)", "name", "", None)]) assert_node(doctree[1], addnodes.desc, domain="js", objtype="data", noindex=False) + + +def test_noindexentry(app): + text = (".. js:function:: f()\n" + ".. js:function:: g()\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('single', 'f() (built-in function)', 'f', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 98b295b99..fe117659a 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -4,10 +4,11 @@ Tests the Python Domain - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import re import sys from unittest.mock import Mock @@ -15,15 +16,13 @@ import pytest from docutils import nodes from sphinx import addnodes -from sphinx.addnodes import ( - desc, desc_addname, desc_annotation, desc_content, desc_name, desc_optional, - desc_parameter, desc_parameterlist, desc_returns, desc_signature, - desc_sig_name, desc_sig_operator, desc_sig_punctuation, pending_xref, -) +from sphinx.addnodes import (desc, desc_addname, desc_annotation, desc_content, desc_name, + desc_optional, desc_parameter, desc_parameterlist, desc_returns, + desc_sig_name, desc_sig_operator, desc_sig_punctuation, + desc_signature, pending_xref) from sphinx.domains import IndexEntry -from sphinx.domains.python import ( - py_sig_re, _parse_annotation, _pseudo_parse_arglist, PythonDomain, PythonModuleIndex -) +from sphinx.domains.python import (PythonDomain, PythonModuleIndex, _parse_annotation, + _pseudo_parse_arglist, py_sig_re) from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node @@ -134,6 +133,29 @@ def test_domain_py_xrefs(app, status, warning): assert len(refnodes) == 2 +@pytest.mark.sphinx('html', testroot='domain-py') +def test_domain_py_xrefs_abbreviations(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'abbr.html').read_text() + assert re.search(r'normal: <a .* href="module.html#module_a.submodule.ModTopLevel.' + r'mod_child_1" .*><.*>module_a.submodule.ModTopLevel.mod_child_1\(\)' + r'<.*></a>', + content) + assert re.search(r'relative: <a .* href="module.html#module_a.submodule.ModTopLevel.' + r'mod_child_1" .*><.*>ModTopLevel.mod_child_1\(\)<.*></a>', + content) + assert re.search(r'short name: <a .* href="module.html#module_a.submodule.ModTopLevel.' + r'mod_child_1" .*><.*>mod_child_1\(\)<.*></a>', + content) + assert re.search(r'relative \+ short name: <a .* href="module.html#module_a.submodule.' + r'ModTopLevel.mod_child_1" .*><.*>mod_child_1\(\)<.*></a>', + content) + assert re.search(r'short name \+ relative: <a .* href="module.html#module_a.submodule.' + r'ModTopLevel.mod_child_1" .*><.*>mod_child_1\(\)<.*></a>', + content) + + @pytest.mark.sphinx('dummy', testroot='domain-py') def test_domain_py_objects(app, status, warning): app.builder.build_all() @@ -236,18 +258,18 @@ def test_get_full_qualified_name(): assert domain.get_full_qualified_name(node) == 'module1.Class.func' -def test_parse_annotation(): - doctree = _parse_annotation("int") +def test_parse_annotation(app): + doctree = _parse_annotation("int", app.env) assert_node(doctree, ([pending_xref, "int"],)) assert_node(doctree[0], pending_xref, refdomain="py", reftype="class", reftarget="int") - doctree = _parse_annotation("List[int]") + doctree = _parse_annotation("List[int]", app.env) assert_node(doctree, ([pending_xref, "List"], [desc_sig_punctuation, "["], [pending_xref, "int"], [desc_sig_punctuation, "]"])) - doctree = _parse_annotation("Tuple[int, int]") + doctree = _parse_annotation("Tuple[int, int]", app.env) assert_node(doctree, ([pending_xref, "Tuple"], [desc_sig_punctuation, "["], [pending_xref, "int"], @@ -255,14 +277,22 @@ def test_parse_annotation(): [pending_xref, "int"], [desc_sig_punctuation, "]"])) - doctree = _parse_annotation("Tuple[()]") + doctree = _parse_annotation("Tuple[()]", app.env) assert_node(doctree, ([pending_xref, "Tuple"], [desc_sig_punctuation, "["], [desc_sig_punctuation, "("], [desc_sig_punctuation, ")"], [desc_sig_punctuation, "]"])) - doctree = _parse_annotation("Callable[[int, int], int]") + doctree = _parse_annotation("Tuple[int, ...]", app.env) + assert_node(doctree, ([pending_xref, "Tuple"], + [desc_sig_punctuation, "["], + [pending_xref, "int"], + [desc_sig_punctuation, ", "], + [desc_sig_punctuation, "..."], + [desc_sig_punctuation, "]"])) + + doctree = _parse_annotation("Callable[[int, int], int]", app.env) assert_node(doctree, ([pending_xref, "Callable"], [desc_sig_punctuation, "["], [desc_sig_punctuation, "["], @@ -274,13 +304,18 @@ def test_parse_annotation(): [pending_xref, "int"], [desc_sig_punctuation, "]"])) + doctree = _parse_annotation("List[None]", app.env) + assert_node(doctree, ([pending_xref, "List"], + [desc_sig_punctuation, "["], + [pending_xref, "None"], + [desc_sig_punctuation, "]"])) + # None type makes an object-reference (not a class reference) - doctree = _parse_annotation("None") + doctree = _parse_annotation("None", app.env) assert_node(doctree, ([pending_xref, "None"],)) assert_node(doctree[0], pending_xref, refdomain="py", reftype="obj", reftarget="None") - def test_pyfunction_signature(app): text = ".. py:function:: hello(name: str) -> str" doctree = restructuredtext.parse(app, text) @@ -300,7 +335,7 @@ def test_pyfunction_signature(app): def test_pyfunction_signature_full(app): text = (".. py:function:: hello(a: str, b = 1, *args: str, " - "c: bool = True, **kwargs: str) -> str") + "c: bool = True, d: tuple = (1, 2), **kwargs: str) -> str") doctree = restructuredtext.parse(app, text) assert_node(doctree, (addnodes.index, [desc, ([desc_signature, ([desc_name, "hello"], @@ -330,6 +365,14 @@ def test_pyfunction_signature_full(app): [desc_sig_operator, "="], " ", [nodes.inline, "True"])], + [desc_parameter, ([desc_sig_name, "d"], + [desc_sig_punctuation, ":"], + " ", + [desc_sig_name, pending_xref, "tuple"], + " ", + [desc_sig_operator, "="], + " ", + [nodes.inline, "(1, 2)"])], [desc_parameter, ([desc_sig_operator, "**"], [desc_sig_name, "kwargs"], [desc_sig_punctuation, ":"], @@ -373,6 +416,19 @@ def test_pyfunction_signature_full_py38(app): [desc_parameter, desc_sig_operator, "/"])]) +@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.') +def test_pyfunction_with_number_literals(app): + text = ".. py:function:: hello(age=0x10, height=1_6_0)" + doctree = restructuredtext.parse(app, text) + assert_node(doctree[1][0][1], + [desc_parameterlist, ([desc_parameter, ([desc_sig_name, "age"], + [desc_sig_operator, "="], + [nodes.inline, "0x10"])], + [desc_parameter, ([desc_sig_name, "height"], + [desc_sig_operator, "="], + [nodes.inline, "1_6_0"])])]) + + def test_optional_pyfunction_signature(app): text = ".. py:function:: compile(source [, filename [, symbol]]) -> ast object" doctree = restructuredtext.parse(app, text) @@ -458,14 +514,22 @@ def test_pyobject_prefix(app): def test_pydata(app): - text = ".. py:data:: var\n" + text = (".. py:module:: example\n" + ".. py:data:: var\n" + " :type: int\n") domain = app.env.get_domain('py') doctree = restructuredtext.parse(app, text) - assert_node(doctree, (addnodes.index, - [desc, ([desc_signature, desc_name, "var"], + assert_node(doctree, (nodes.target, + addnodes.index, + addnodes.index, + [desc, ([desc_signature, ([desc_addname, "example."], + [desc_name, "var"], + [desc_annotation, (": ", + [pending_xref, "int"])])], [desc_content, ()])])) - assert 'var' in domain.objects - assert domain.objects['var'] == ('index', 'var', 'data') + assert_node(doctree[3][0][2][1], pending_xref, **{"py:module": "example"}) + assert 'example.var' in domain.objects + assert domain.objects['example.var'] == ('index', 'example.var', 'data') def test_pyfunction(app): @@ -679,7 +743,7 @@ def test_pyattribute(app): text = (".. py:class:: Class\n" "\n" " .. py:attribute:: attr\n" - " :type: str\n" + " :type: Optional[str]\n" " :value: ''\n") domain = app.env.get_domain('py') doctree = restructuredtext.parse(app, text) @@ -692,9 +756,14 @@ def test_pyattribute(app): entries=[('single', 'attr (Class attribute)', 'Class.attr', '', None)]) assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "attr"], [desc_annotation, (": ", - [pending_xref, "str"])], + [pending_xref, "Optional"], + [desc_sig_punctuation, "["], + [pending_xref, "str"], + [desc_sig_punctuation, "]"])], [desc_annotation, " = ''"])], [desc_content, ()])) + assert_node(doctree[1][1][1][0][1][1], pending_xref, **{"py:class": "Class"}) + assert_node(doctree[1][1][1][0][1][3], pending_xref, **{"py:class": "Class"}) assert 'Class.attr' in domain.objects assert domain.objects['Class.attr'] == ('index', 'Class.attr', 'attribute') @@ -729,6 +798,53 @@ def test_pydecoratormethod_signature(app): assert domain.objects['deco'] == ('index', 'deco', 'method') +def test_info_field_list(app): + text = (".. py:module:: example\n" + ".. py:class:: Class\n" + "\n" + " :param str name: blah blah\n" + " :param age: blah blah\n" + " :type age: int\n") + doctree = restructuredtext.parse(app, text) + print(doctree) + + assert_node(doctree, (nodes.target, + addnodes.index, + addnodes.index, + [desc, ([desc_signature, ([desc_annotation, "class "], + [desc_addname, "example."], + [desc_name, "Class"])], + [desc_content, nodes.field_list, nodes.field])])) + assert_node(doctree[3][1][0][0], + ([nodes.field_name, "Parameters"], + [nodes.field_body, nodes.bullet_list, ([nodes.list_item, nodes.paragraph], + [nodes.list_item, nodes.paragraph])])) + + # :param str name: + assert_node(doctree[3][1][0][0][1][0][0][0], + ([addnodes.literal_strong, "name"], + " (", + [pending_xref, addnodes.literal_emphasis, "str"], + ")", + " -- ", + "blah blah")) + assert_node(doctree[3][1][0][0][1][0][0][0][2], pending_xref, + refdomain="py", reftype="class", reftarget="str", + **{"py:module": "example", "py:class": "Class"}) + + # :param age: + :type age: + assert_node(doctree[3][1][0][0][1][0][1][0], + ([addnodes.literal_strong, "age"], + " (", + [pending_xref, addnodes.literal_emphasis, "int"], + ")", + " -- ", + "blah blah")) + assert_node(doctree[3][1][0][0][1][0][1][0][2], pending_xref, + refdomain="py", reftype="class", reftarget="int", + **{"py:module": "example", "py:class": "Class"}) + + @pytest.mark.sphinx(freshenv=True) def test_module_index(app): text = (".. py:module:: docutils\n" @@ -796,3 +912,27 @@ def test_modindex_common_prefix(app): ) +def test_noindexentry(app): + text = (".. py:function:: f()\n" + ".. py:function:: g()\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('pair', 'built-in function; f()', 'f', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) + + text = (".. py:class:: f\n" + ".. py:class:: g\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('single', 'f (built-in class)', 'f', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) + + +@pytest.mark.sphinx('dummy', testroot='domain-py-xref-warning') +def test_warn_missing_reference(app, status, warning): + app.build() + assert 'index.rst:6: WARNING: undefined label: no-label' in warning.getvalue() + assert ('index.rst:6: WARNING: Failed to create a cross reference. A title or caption not found: existing-label' + in warning.getvalue()) diff --git a/tests/test_domain_rst.py b/tests/test_domain_rst.py index 86fe7ef3f..ed542ed35 100644 --- a/tests/test_domain_rst.py +++ b/tests/test_domain_rst.py @@ -4,14 +4,13 @@ Tests the reStructuredText domain. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from sphinx import addnodes -from sphinx.addnodes import ( - desc, desc_addname, desc_annotation, desc_content, desc_name, desc_signature -) +from sphinx.addnodes import (desc, desc_addname, desc_annotation, desc_content, desc_name, + desc_signature) from sphinx.domains.rst import parse_directive from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py index 33a000a3f..cf32e7964 100644 --- a/tests/test_domain_std.py +++ b/tests/test_domain_std.py @@ -4,24 +4,20 @@ Tests the std domain - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -import pytest - from unittest import mock +import pytest from docutils import nodes from docutils.nodes import definition, definition_list, definition_list_item, term - from html5lib import HTMLParser from sphinx import addnodes -from sphinx.addnodes import ( - desc, desc_addname, desc_content, desc_name, desc_signature, glossary, index, - pending_xref -) +from sphinx.addnodes import (desc, desc_addname, desc_content, desc_name, desc_signature, + glossary, index, pending_xref) from sphinx.domains.std import StandardDomain from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node @@ -95,6 +91,28 @@ def test_get_full_qualified_name(): assert domain.get_full_qualified_name(node) == 'ls.-l' +def test_cmd_option_with_optional_value(app): + text = ".. option:: -j[=N]" + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (index, + [desc, ([desc_signature, ([desc_name, '-j'], + [desc_addname, '[=N]'])], + [desc_content, ()])])) + objects = list(app.env.get_domain("std").get_objects()) + assert ('-j', '-j', 'cmdoption', 'index', 'cmdoption-j', 1) in objects + + +def test_cmd_option_starting_with_bracket(app): + text = ".. option:: [enable=]PATTERN" + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (index, + [desc, ([desc_signature, ([desc_name, '[enable'], + [desc_addname, '=]PATTERN'])], + [desc_content, ()])])) + objects = list(app.env.get_domain("std").get_objects()) + assert ('[enable', '[enable', 'cmdoption', 'index', 'cmdoption-arg-enable', 1) in objects + + def test_glossary(app): text = (".. glossary::\n" "\n" @@ -337,7 +355,7 @@ def test_multiple_cmdoptions(app): def test_productionlist(app, status, warning): app.builder.build_all() - warnings = warning.getvalue().split("\n"); + warnings = warning.getvalue().split("\n") assert len(warnings) == 2 assert warnings[-1] == '' assert "Dup2.rst:4: WARNING: duplicate token description of Dup, other instance in Dup1" in warnings[0] @@ -387,6 +405,22 @@ def test_productionlist(app, status, warning): assert "A</strong> ::= B C D E F G" in text +def test_productionlist2(app): + text = (".. productionlist:: P2\n" + " A: `:A` `A`\n" + " B: `P1:B` `~P1:B`\n") + doctree = restructuredtext.parse(app, text) + refnodes = list(doctree.traverse(pending_xref)) + assert_node(refnodes[0], pending_xref, reftarget="A") + assert_node(refnodes[1], pending_xref, reftarget="P2:A") + assert_node(refnodes[2], pending_xref, reftarget="P1:B") + assert_node(refnodes[3], pending_xref, reftarget="P1:B") + assert_node(refnodes[0], [pending_xref, nodes.literal, "A"]) + assert_node(refnodes[1], [pending_xref, nodes.literal, "A"]) + assert_node(refnodes[2], [pending_xref, nodes.literal, "P1:B"]) + assert_node(refnodes[3], [pending_xref, nodes.literal, "B"]) + + def test_disabled_docref(app): text = (":doc:`index`\n" ":doc:`!index`\n") @@ -394,3 +428,13 @@ def test_disabled_docref(app): assert_node(doctree, ([nodes.paragraph, ([pending_xref, nodes.inline, "index"], "\n", [nodes.inline, "index"])],)) + + +def test_labeled_rubric(app): + text = (".. _label:\n" + ".. rubric:: blah *blah* blah\n") + restructuredtext.parse(app, text) + + domain = app.env.get_domain("std") + assert 'label' in domain.labels + assert domain.labels['label'] == ('index', 'label', 'blah blah blah') diff --git a/tests/test_environment.py b/tests/test_environment.py index 7290eb6a0..9791c2d5b 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -4,16 +4,17 @@ Test the BuildEnvironment class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import shutil + import pytest from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.latex import LaTeXBuilder -from sphinx.environment import CONFIG_OK, CONFIG_CHANGED, CONFIG_EXTENSIONS_CHANGED, CONFIG_NEW +from sphinx.environment import CONFIG_CHANGED, CONFIG_EXTENSIONS_CHANGED, CONFIG_NEW, CONFIG_OK from sphinx.testing.comparer import PathComparer @@ -137,6 +138,11 @@ def test_env_relfn2path(app): assert relfn == '../logo.jpg' assert absfn == app.srcdir.parent / 'logo.jpg' + # relative path traversal + relfn, absfn = app.env.relfn2path('subdir/../logo.jpg', 'index') + assert relfn == 'logo.jpg' + assert absfn == app.srcdir / 'logo.jpg' + # omit docname (w/ current docname) app.env.temp_data['docname'] = 'subdir/document' relfn, absfn = app.env.relfn2path('images/logo.jpg') diff --git a/tests/test_environment_indexentries.py b/tests/test_environment_indexentries.py index 7f6003d54..1b549bacb 100644 --- a/tests/test_environment_indexentries.py +++ b/tests/test_environment_indexentries.py @@ -4,7 +4,7 @@ Test the sphinx.environment.managers.indexentries. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -23,22 +23,27 @@ def test_create_single_index(app): ".. index:: Sphinx\n" ".. index:: Ель\n" ".. index:: ёлка\n" - ".. index:: תירבע\n" + ".. index:: עברית\n" ".. index:: 9-symbol\n" - ".. index:: &-symbol\n") + ".. index:: &-symbol\n" + ".. index:: £100\n") restructuredtext.parse(app, text) index = IndexEntries(app.env).create_index(app.builder) assert len(index) == 6 assert index[0] == ('Symbols', [('&-symbol', [[('', '#index-9')], [], None]), - ('9-symbol', [[('', '#index-8')], [], None])]) + ('9-symbol', [[('', '#index-8')], [], None]), + ('£100', [[('', '#index-10')], [], None])]) assert index[1] == ('D', [('docutils', [[('', '#index-0')], [], None])]) assert index[2] == ('P', [('pip', [[], [('install', [('', '#index-2')]), ('upgrade', [('', '#index-3')])], None]), ('Python', [[('', '#index-1')], [], None])]) assert index[3] == ('S', [('Sphinx', [[('', '#index-4')], [], None])]) - assert index[4] == ('Е', [('ёлка', [[('', '#index-6')], [], None]), - ('Ель', [[('', '#index-5')], [], None])]) - assert index[5] == ('ת', [('תירבע', [[('', '#index-7')], [], None])]) + assert index[4] == ('Е', + [('ёлка', [[('', '#index-6')], [], None]), + ('Ель', [[('', '#index-5')], [], None])]) + # Here the word starts with U+200F RIGHT-TO-LEFT MARK, which should be + # ignored when getting the first letter. + assert index[5] == ('ע', [('עברית', [[('', '#index-7')], [], None])]) @pytest.mark.sphinx('dummy', freshenv=True) @@ -67,8 +72,9 @@ def test_create_pair_index(app): ('ёлка', [('', '#index-5')]), ('Ель', [('', '#index-4')])], None])]) - assert index[6] == ('Е', [('ёлка', [[], [('Sphinx', [('', '#index-5')])], None]), - ('Ель', [[], [('Sphinx', [('', '#index-4')])], None])]) + assert index[6] == ('Е', + [('ёлка', [[], [('Sphinx', [('', '#index-5')])], None]), + ('Ель', [[], [('Sphinx', [('', '#index-4')])], None])]) @pytest.mark.sphinx('dummy', freshenv=True) diff --git a/tests/test_environment_toctree.py b/tests/test_environment_toctree.py index a8c7da62e..41b3f727c 100644 --- a/tests/test_environment_toctree.py +++ b/tests/test_environment_toctree.py @@ -4,13 +4,13 @@ Test the sphinx.environment.managers.toctree. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest from docutils import nodes -from docutils.nodes import bullet_list, list_item, caption, comment, reference +from docutils.nodes import bullet_list, caption, comment, list_item, reference from sphinx import addnodes from sphinx.addnodes import compact_paragraph, only @@ -41,7 +41,8 @@ def test_process_doc(app): assert_node(toctree[0][1][0], addnodes.toctree, caption="Table of Contents", glob=False, hidden=False, titlesonly=False, maxdepth=2, numbered=999, - entries=[(None, 'foo'), (None, 'bar'), (None, 'http://sphinx-doc.org/')], + entries=[(None, 'foo'), (None, 'bar'), (None, 'http://sphinx-doc.org/'), + (None, 'self')], includefiles=['foo', 'bar']) # only branch @@ -219,7 +220,9 @@ def test_get_toctree_for(app): ([list_item, ([compact_paragraph, reference, "foo"], bullet_list)], [list_item, compact_paragraph, reference, "bar"], - [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"])) + [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"], + [list_item, compact_paragraph, reference, + "Welcome to Sphinx Tests’s documentation!"])) assert_node(toctree[1][0][1], ([list_item, compact_paragraph, reference, "quux"], [list_item, compact_paragraph, reference, "foo.1"], @@ -231,6 +234,7 @@ def test_get_toctree_for(app): assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3]) assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") + assert_node(toctree[1][3][0][0], reference, refuri="") assert_node(toctree[2], [bullet_list, list_item, compact_paragraph, reference, "baz"]) @@ -255,10 +259,13 @@ def test_get_toctree_for_collapse(app): assert_node(toctree[1], ([list_item, compact_paragraph, reference, "foo"], [list_item, compact_paragraph, reference, "bar"], - [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"])) + [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"], + [list_item, compact_paragraph, reference, + "Welcome to Sphinx Tests’s documentation!"])) assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1]) assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") + assert_node(toctree[1][3][0][0], reference, refuri="") assert_node(toctree[2], [bullet_list, list_item, compact_paragraph, reference, "baz"]) @@ -285,7 +292,9 @@ def test_get_toctree_for_maxdepth(app): ([list_item, ([compact_paragraph, reference, "foo"], bullet_list)], [list_item, compact_paragraph, reference, "bar"], - [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"])) + [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"], + [list_item, compact_paragraph, reference, + "Welcome to Sphinx Tests’s documentation!"])) assert_node(toctree[1][0][1], ([list_item, compact_paragraph, reference, "quux"], [list_item, ([compact_paragraph, reference, "foo.1"], @@ -302,6 +311,7 @@ def test_get_toctree_for_maxdepth(app): assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3]) assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2]) assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/") + assert_node(toctree[1][3][0][0], reference, refuri="") assert_node(toctree[2], [bullet_list, list_item, compact_paragraph, reference, "baz"]) @@ -327,7 +337,9 @@ def test_get_toctree_for_includehidden(app): ([list_item, ([compact_paragraph, reference, "foo"], bullet_list)], [list_item, compact_paragraph, reference, "bar"], - [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"])) + [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"], + [list_item, compact_paragraph, reference, + "Welcome to Sphinx Tests’s documentation!"])) assert_node(toctree[1][0][1], ([list_item, compact_paragraph, reference, "quux"], [list_item, compact_paragraph, reference, "foo.1"], diff --git a/tests/test_events.py b/tests/test_events.py index 4fbe03a17..bfff7a30f 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -4,7 +4,7 @@ Test the EventManager class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_apidoc.py b/tests/test_ext_apidoc.py index e8d923b71..d6c45c268 100644 --- a/tests/test_ext_apidoc.py +++ b/tests/test_ext_apidoc.py @@ -4,7 +4,7 @@ Test the sphinx.apidoc module. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -121,7 +121,6 @@ def test_pep_0420_enabled_separate(make_app, apidoc): with open(outdir / 'a.b.c.rst') as f: rst = f.read() - assert ".. toctree::\n :maxdepth: 4\n\n a.b.c.d\n" in rst with open(outdir / 'a.b.e.rst') as f: @@ -217,6 +216,8 @@ def test_trailing_underscore(make_app, apidoc): def test_excludes(apidoc): outdir = apidoc.outdir assert (outdir / 'conf.py').isfile() + assert (outdir / 'a.rst').isfile() + assert (outdir / 'a.b.rst').isfile() assert (outdir / 'a.b.c.rst').isfile() # generated because not empty assert not (outdir / 'a.b.e.rst').isfile() # skipped because of empty after excludes assert (outdir / 'a.b.x.rst').isfile() @@ -232,6 +233,8 @@ def test_excludes_subpackage_should_be_skipped(apidoc): """Subpackage exclusion should work.""" outdir = apidoc.outdir assert (outdir / 'conf.py').isfile() + assert (outdir / 'a.rst').isfile() + assert (outdir / 'a.b.rst').isfile() assert (outdir / 'a.b.c.rst').isfile() # generated because not empty assert not (outdir / 'a.b.e.f.rst').isfile() # skipped because 'b/e' subpackage is skipped @@ -245,6 +248,8 @@ def test_excludes_module_should_be_skipped(apidoc): """Module exclusion should work.""" outdir = apidoc.outdir assert (outdir / 'conf.py').isfile() + assert (outdir / 'a.rst').isfile() + assert (outdir / 'a.b.rst').isfile() assert (outdir / 'a.b.c.rst').isfile() # generated because not empty assert not (outdir / 'a.b.e.f.rst').isfile() # skipped because of empty after excludes @@ -258,6 +263,8 @@ def test_excludes_module_should_not_be_skipped(apidoc): """Module should be included if no excludes are used.""" outdir = apidoc.outdir assert (outdir / 'conf.py').isfile() + assert (outdir / 'a.rst').isfile() + assert (outdir / 'a.b.rst').isfile() assert (outdir / 'a.b.c.rst').isfile() # generated because not empty assert (outdir / 'a.b.e.f.rst').isfile() # skipped because of empty after excludes @@ -509,7 +516,6 @@ def test_package_file(tempdir): " :undoc-members:\n" " :show-inheritance:\n" "\n" - "\n" "Module contents\n" "---------------\n" "\n" @@ -595,8 +601,7 @@ def test_package_file_module_first(tempdir): ".. automodule:: testpkg.example\n" " :members:\n" " :undoc-members:\n" - " :show-inheritance:\n" - "\n") + " :show-inheritance:\n") def test_package_file_without_submodules(tempdir): @@ -639,5 +644,4 @@ def test_namespace_package_file(tempdir): ".. automodule:: testpkg.example\n" " :members:\n" " :undoc-members:\n" - " :show-inheritance:\n" - "\n") + " :show-inheritance:\n") diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 5cc1f3c22..d555359cf 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -5,7 +5,7 @@ Test the autodoc extension. This tests mainly the Documenters; the auto directives are tested in a test source file translated by test_build. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -17,7 +17,7 @@ import pytest from docutils.statemachine import ViewList from sphinx import addnodes -from sphinx.ext.autodoc import ModuleLevelDocumenter, ALL, Options +from sphinx.ext.autodoc import ALL, ModuleLevelDocumenter, Options from sphinx.ext.autodoc.directive import DocumenterBridge, process_documenter_options from sphinx.testing.util import SphinxTestApp, Struct # NOQA from sphinx.util.docutils import LoggingReporter @@ -121,15 +121,16 @@ def test_parse_name(app): verify('class', 'Base', ('test_ext_autodoc', ['Base'], None, None)) # for members - directive.env.ref_context['py:module'] = 'foo' - verify('method', 'util.SphinxTestApp.cleanup', - ('foo', ['util', 'SphinxTestApp', 'cleanup'], None, None)) - directive.env.ref_context['py:module'] = 'util' + directive.env.ref_context['py:module'] = 'sphinx.testing.util' + verify('method', 'SphinxTestApp.cleanup', + ('sphinx.testing.util', ['SphinxTestApp', 'cleanup'], None, None)) + directive.env.ref_context['py:module'] = 'sphinx.testing.util' directive.env.ref_context['py:class'] = 'Foo' directive.env.temp_data['autodoc:class'] = 'SphinxTestApp' - verify('method', 'cleanup', ('util', ['SphinxTestApp', 'cleanup'], None, None)) + verify('method', 'cleanup', + ('sphinx.testing.util', ['SphinxTestApp', 'cleanup'], None, None)) verify('method', 'SphinxTestApp.cleanup', - ('util', ['SphinxTestApp', 'cleanup'], None, None)) + ('sphinx.testing.util', ['SphinxTestApp', 'cleanup'], None, None)) def test_format_signature(app): @@ -176,7 +177,6 @@ def test_format_signature(app): for C in (D, E): assert formatsig('class', 'D', C, None, None) == '()' - class SomeMeta(type): def __call__(cls, a, b=None): return type.__call__(cls, a, b) @@ -208,7 +208,6 @@ def test_format_signature(app): assert formatsig('class', 'C', C, None, None) == '(a, b=None)' assert formatsig('class', 'C', D, 'a, b', 'X') == '(a, b) -> X' - class ListSubclass(list): pass @@ -218,7 +217,6 @@ def test_format_signature(app): else: assert formatsig('class', 'C', ListSubclass, None, None) == '' - class ExceptionSubclass(Exception): pass @@ -226,7 +224,6 @@ def test_format_signature(app): if getattr(Exception, '__text_signature__', None) is None: assert formatsig('class', 'C', ExceptionSubclass, None, None) == '' - # __init__ have signature at first line of docstring directive.env.config.autoclass_content = 'both' @@ -289,6 +286,21 @@ def test_format_signature(app): '(b, c=42, *d, **e)' +@pytest.mark.skipif(sys.version_info < (3, 5), reason='typing is available since python3.5.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodoc_process_signature_typing_generic(app): + actual = do_autodoc(app, 'class', 'target.generic_class.A', {}) + + assert list(actual) == [ + '', + '.. py:class:: A(a, b=None)', + ' :module: target.generic_class', + '', + ' docstring for A', + '', + ] + + def test_autodoc_process_signature_typehints(app): captured = [] @@ -355,11 +367,6 @@ def test_get_doc(app): """Döcstring""" assert getdocl('function', f) == ['Döcstring'] - # already-unicode docstrings must be taken literally - def f(): - """Döcstring""" - assert getdocl('function', f) == ['Döcstring'] - # verify that method docstrings get extracted in both normal case # and in case of bound method posing as a function class J: # NOQA @@ -683,6 +690,7 @@ def test_autodoc_special_members(app): actual = do_autodoc(app, 'class', 'target.Class', options) assert list(filter(lambda l: '::' in l, actual)) == [ '.. py:class:: Class(arg)', + ' .. py:attribute:: Class.__annotations__', ' .. py:attribute:: Class.__dict__', ' .. py:method:: Class.__init__(arg)', ' .. py:attribute:: Class.__module__', @@ -794,20 +802,20 @@ def test_autodoc_inner_class(app): ' .. py:attribute:: Outer.factory', ' :module: target', '', - ' alias of :class:`builtins.dict`' + ' alias of :class:`dict`' ] actual = do_autodoc(app, 'class', 'target.Outer.Inner', options) assert list(actual) == [ '', - '.. py:class:: Outer.Inner()', - ' :module: target', + '.. py:class:: Inner()', + ' :module: target.Outer', '', ' Foo', '', '', - ' .. py:method:: Outer.Inner.meth()', - ' :module: target', + ' .. py:method:: Inner.meth()', + ' :module: target.Outer', '', ' Foo', '', @@ -880,6 +888,26 @@ def test_autodoc_descriptor(app): ] +@pytest.mark.skipif(sys.version_info < (3, 8), + reason='cached_property is available since python3.8.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodoc_cached_property(app): + options = {"members": None, + "undoc-members": True} + actual = do_autodoc(app, 'class', 'target.cached_property.Foo', options) + assert list(actual) == [ + '', + '.. py:class:: Foo()', + ' :module: target.cached_property', + '', + '', + ' .. py:method:: Foo.prop', + ' :module: target.cached_property', + ' :property:', + '', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_member_order(app): # case member-order='bysource' @@ -1046,7 +1074,7 @@ def test_class_attributes(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') -def test_instance_attributes(app): +def test_autoclass_instance_attributes(app): options = {"members": None} actual = do_autodoc(app, 'class', 'target.InstAttCls', options) assert list(actual) == [ @@ -1120,6 +1148,19 @@ def test_instance_attributes(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_instance_attributes(app): + actual = do_autodoc(app, 'attribute', 'target.InstAttCls.ia1') + assert list(actual) == [ + '', + '.. py:attribute:: InstAttCls.ia1', + ' :module: target', + '', + ' Doc comment for instance attribute InstAttCls.ia1', + '' + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') def test_slots(app): options = {"members": None, "undoc-members": True} @@ -1132,6 +1173,8 @@ def test_slots(app): '.. py:class:: Bar()', ' :module: target.slots', '', + ' docstring', + '', '', ' .. py:attribute:: Bar.attr1', ' :module: target.slots', @@ -1149,9 +1192,21 @@ def test_slots(app): ' :module: target.slots', '', '', + '.. py:class:: Baz()', + ' :module: target.slots', + '', + ' docstring', + '', + '', + ' .. py:attribute:: Baz.attr', + ' :module: target.slots', + '', + '', '.. py:class:: Foo()', ' :module: target.slots', '', + ' docstring', + '', '', ' .. py:attribute:: Foo.attr', ' :module: target.slots', @@ -1162,44 +1217,44 @@ def test_slots(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_enum_class(app): options = {"members": None} - actual = do_autodoc(app, 'class', 'target.enum.EnumCls', options) + actual = do_autodoc(app, 'class', 'target.enums.EnumCls', options) assert list(actual) == [ '', '.. py:class:: EnumCls(value)', - ' :module: target.enum', + ' :module: target.enums', '', ' this is enum class', '', '', ' .. py:method:: EnumCls.say_goodbye()', - ' :module: target.enum', + ' :module: target.enums', ' :classmethod:', '', ' a classmethod says good-bye to you.', '', '', ' .. py:method:: EnumCls.say_hello()', - ' :module: target.enum', + ' :module: target.enums', '', ' a method says hello to you.', '', '', ' .. py:attribute:: EnumCls.val1', - ' :module: target.enum', + ' :module: target.enums', ' :value: 12', '', ' doc for val1', '', '', ' .. py:attribute:: EnumCls.val2', - ' :module: target.enum', + ' :module: target.enums', ' :value: 23', '', ' doc for val2', '', '', ' .. py:attribute:: EnumCls.val3', - ' :module: target.enum', + ' :module: target.enums', ' :value: 34', '', ' doc for val3', @@ -1207,11 +1262,11 @@ def test_enum_class(app): ] # checks for an attribute of EnumClass - actual = do_autodoc(app, 'attribute', 'target.enum.EnumCls.val1') + actual = do_autodoc(app, 'attribute', 'target.enums.EnumCls.val1') assert list(actual) == [ '', '.. py:attribute:: EnumCls.val1', - ' :module: target.enum', + ' :module: target.enums', ' :value: 12', '', ' doc for val1', @@ -1266,7 +1321,7 @@ def test_automethod_for_decorated(app): actual = do_autodoc(app, 'method', 'target.decorator.Bar.meth') assert list(actual) == [ '', - '.. py:method:: Bar.meth()', + '.. py:method:: Bar.meth(name=None, age=None)', ' :module: target.decorator', '', ] @@ -1431,7 +1486,7 @@ def test_coroutine(app): actual = do_autodoc(app, 'function', 'target.coroutine.sync_func') assert list(actual) == [ '', - '.. py:function:: sync_func(*args, **kwargs)', + '.. py:function:: sync_func()', ' :module: target.coroutine', '', ] @@ -1513,6 +1568,11 @@ def test_autodoc_typed_instance_variables(app): '.. py:module:: target.typed_vars', '', '', + '.. py:attribute:: Alias', + ' :module: target.typed_vars', + '', + ' alias of :class:`target.typed_vars.Derived`', + '', '.. py:class:: Class()', ' :module: target.typed_vars', '', @@ -1562,6 +1622,15 @@ def test_autodoc_typed_instance_variables(app): ' This is descr4', '', '', + '.. py:class:: Derived()', + ' :module: target.typed_vars', + '', + '', + ' .. py:attribute:: Derived.attr7', + ' :module: target.typed_vars', + ' :type: int', + '', + '', '.. py:data:: attr1', ' :module: target.typed_vars', ' :type: str', @@ -1587,6 +1656,69 @@ def test_autodoc_typed_instance_variables(app): ] +@pytest.mark.skipif(sys.version_info < (3, 6), reason='py36+ is available since python3.6.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodoc_typed_inherited_instance_variables(app): + options = {"members": None, + "undoc-members": True, + "inherited-members": True} + actual = do_autodoc(app, 'class', 'target.typed_vars.Derived', options) + assert list(actual) == [ + '', + '.. py:class:: Derived()', + ' :module: target.typed_vars', + '', + '', + ' .. py:attribute:: Derived.attr1', + ' :module: target.typed_vars', + ' :type: int', + ' :value: 0', + '', + '', + ' .. py:attribute:: Derived.attr2', + ' :module: target.typed_vars', + ' :type: int', + '', + '', + ' .. py:attribute:: Derived.attr3', + ' :module: target.typed_vars', + ' :type: int', + ' :value: 0', + '', + '', + ' .. py:attribute:: Derived.attr4', + ' :module: target.typed_vars', + ' :type: int', + '', + ' attr4', + '', + '', + ' .. py:attribute:: Derived.attr5', + ' :module: target.typed_vars', + ' :type: int', + '', + ' attr5', + '', + '', + ' .. py:attribute:: Derived.attr6', + ' :module: target.typed_vars', + ' :type: int', + '', + ' attr6', + '', + '', + ' .. py:attribute:: Derived.attr7', + ' :module: target.typed_vars', + ' :type: int', + '', + '', + ' .. py:attribute:: Derived.descr4', + ' :module: target.typed_vars', + ' :type: int', + '', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_GenericAlias(app): options = {"members": None, @@ -1598,10 +1730,19 @@ def test_autodoc_GenericAlias(app): '.. py:module:: target.genericalias', '', '', + '.. py:class:: Class()', + ' :module: target.genericalias', + '', + '', + ' .. py:attribute:: Class.T', + ' :module: target.genericalias', + '', + ' alias of :class:`List`\\ [:class:`int`]', + '', '.. py:attribute:: T', ' :module: target.genericalias', '', - ' alias of :class:`typing.List`', + ' alias of :class:`List`\\ [:class:`int`]', ] else: assert list(actual) == [ @@ -1609,15 +1750,100 @@ def test_autodoc_GenericAlias(app): '.. py:module:: target.genericalias', '', '', + '.. py:class:: Class()', + ' :module: target.genericalias', + '', + '', + ' .. py:attribute:: Class.T', + ' :module: target.genericalias', + '', + ' A list of int', + '', + ' alias of List[int]', + '', + '', '.. py:data:: T', ' :module: target.genericalias', '', ' A list of int', '', ' alias of List[int]', + '', ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodoc_TypeVar(app): + options = {"members": None, + "undoc-members": None} + actual = do_autodoc(app, 'module', 'target.typevar', options) + assert list(actual) == [ + '', + '.. py:module:: target.typevar', + '', + '', + '.. py:class:: Class()', + ' :module: target.typevar', + '', + '', + ' .. py:attribute:: Class.T1', + ' :module: target.typevar', + '', + ' T1', + '', + " alias of TypeVar('T1')", + '', + '', + ' .. py:attribute:: Class.T6', + ' :module: target.typevar', + '', + ' T6', + '', + ' alias of :class:`int`', + '', + '', + '.. py:data:: T1', + ' :module: target.typevar', + '', + ' T1', + '', + " alias of TypeVar('T1')", + '', + '', + '.. py:data:: T3', + ' :module: target.typevar', + '', + ' T3', + '', + " alias of TypeVar('T3', int, str)", + '', + '', + '.. py:data:: T4', + ' :module: target.typevar', + '', + ' T4', + '', + " alias of TypeVar('T4', covariant=True)", + '', + '', + '.. py:data:: T5', + ' :module: target.typevar', + '', + ' T5', + '', + " alias of TypeVar('T5', contravariant=True)", + '', + '', + '.. py:data:: T6', + ' :module: target.typevar', + '', + ' T6', + '', + ' alias of :class:`int`', + '', + ] + + @pytest.mark.skipif(sys.version_info < (3, 9), reason='py39+ is required.') @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_Annotated(app): @@ -1636,6 +1862,28 @@ def test_autodoc_Annotated(app): ] +@pytest.mark.skipif(sys.version_info < (3, 6), reason='py36+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodoc_TYPE_CHECKING(app): + options = {"members": None, + "undoc-members": None} + actual = do_autodoc(app, 'module', 'target.TYPE_CHECKING', options) + assert list(actual) == [ + '', + '.. py:module:: target.TYPE_CHECKING', + '', + '', + '.. py:class:: Foo()', + ' :module: target.TYPE_CHECKING', + '', + '', + ' .. py:attribute:: Foo.attr1', + ' :module: target.TYPE_CHECKING', + ' :type: StringIO', + '', + ] + + @pytest.mark.sphinx('html', testroot='pycode-egg') def test_autodoc_for_egged_code(app): options = {"members": None, @@ -1663,19 +1911,26 @@ def test_autodoc_for_egged_code(app): def test_singledispatch(app): options = {"members": None} actual = do_autodoc(app, 'module', 'target.singledispatch', options) - assert list(actual) == [ - '', - '.. py:module:: target.singledispatch', - '', - '', - '.. py:function:: func(arg, kwarg=None)', - ' func(arg: int, kwarg=None)', - ' func(arg: str, kwarg=None)', - ' :module: target.singledispatch', - '', - ' A function for general use.', - '', - ] + if sys.version_info < (3, 6): + # check the result via "in" because the order of singledispatch signatures is + # usually changed (because dict is not OrderedDict yet!) + assert '.. py:function:: func(arg, kwarg=None)' in actual + assert ' func(arg: int, kwarg=None)' in actual + assert ' func(arg: str, kwarg=None)' in actual + else: + assert list(actual) == [ + '', + '.. py:module:: target.singledispatch', + '', + '', + '.. py:function:: func(arg, kwarg=None)', + ' func(arg: int, kwarg=None)', + ' func(arg: str, kwarg=None)', + ' :module: target.singledispatch', + '', + ' A function for general use.', + '', + ] @pytest.mark.skipif(sys.version_info < (3, 8), @@ -1787,6 +2042,113 @@ def test_final(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_overload(app): + options = {"members": None} + actual = do_autodoc(app, 'module', 'target.overload', options) + assert list(actual) == [ + '', + '.. py:module:: target.overload', + '', + '', + '.. py:class:: Bar(x: int, y: int)', + ' Bar(x: str, y: str)', + ' :module: target.overload', + '', + ' docstring', + '', + '', + '.. py:class:: Baz(x: int, y: int)', + ' Baz(x: str, y: str)', + ' :module: target.overload', + '', + ' docstring', + '', + '', + '.. py:class:: Foo(x: int, y: int)', + ' Foo(x: str, y: str)', + ' :module: target.overload', + '', + ' docstring', + '', + '', + '.. py:class:: Math()', + ' :module: target.overload', + '', + ' docstring', + '', + '', + ' .. py:method:: Math.sum(x: int, y: int = 0) -> int', + ' Math.sum(x: float, y: float = 0.0) -> float', + ' Math.sum(x: str, y: str = None) -> str', + ' :module: target.overload', + '', + ' docstring', + '', + '', + '.. py:function:: sum(x: int, y: int = 0) -> int', + ' sum(x: float, y: float = 0.0) -> float', + ' sum(x: str, y: str = None) -> str', + ' :module: target.overload', + '', + ' docstring', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_overload2(app): + options = {"members": None} + actual = do_autodoc(app, 'module', 'target.overload2', options) + assert list(actual) == [ + '', + '.. py:module:: target.overload2', + '', + '', + '.. py:class:: Baz(x: int, y: int)', + ' Baz(x: str, y: str)', + ' :module: target.overload2', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_pymodule_for_ModuleLevelDocumenter(app): + app.env.ref_context['py:module'] = 'target.classes' + actual = do_autodoc(app, 'class', 'Foo') + assert list(actual) == [ + '', + '.. py:class:: Foo()', + ' :module: target.classes', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_pymodule_for_ClassLevelDocumenter(app): + app.env.ref_context['py:module'] = 'target.methods' + actual = do_autodoc(app, 'method', 'Base.meth') + assert list(actual) == [ + '', + '.. py:method:: Base.meth()', + ' :module: target.methods', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_pyclass_for_ClassLevelDocumenter(app): + app.env.ref_context['py:module'] = 'target.methods' + app.env.ref_context['py:class'] = 'Base' + actual = do_autodoc(app, 'method', 'meth') + assert list(actual) == [ + '', + '.. py:method:: Base.meth()', + ' :module: target.methods', + '', + ] + + @pytest.mark.sphinx('dummy', testroot='ext-autodoc') def test_autodoc(app, status, warning): app.builder.build_all() @@ -1805,3 +2167,117 @@ my_name alias of bug2437.autodoc_dummy_foo.Foo""" assert warning.getvalue() == '' + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_name_conflict(app): + actual = do_autodoc(app, 'class', 'target.name_conflict.foo') + assert list(actual) == [ + '', + '.. py:class:: foo()', + ' :module: target.name_conflict', + '', + ' docstring of target.name_conflict::foo.', + '', + ] + + actual = do_autodoc(app, 'class', 'target.name_conflict.foo.bar') + assert list(actual) == [ + '', + '.. py:class:: bar()', + ' :module: target.name_conflict.foo', + '', + ' docstring of target.name_conflict.foo::bar.', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_name_mangling(app): + options = {"members": None, + "undoc-members": None, + "private-members": None} + actual = do_autodoc(app, 'module', 'target.name_mangling', options) + assert list(actual) == [ + '', + '.. py:module:: target.name_mangling', + '', + '', + '.. py:class:: Bar()', + ' :module: target.name_mangling', + '', + '', + ' .. py:attribute:: Bar._Baz__email', + ' :module: target.name_mangling', + ' :value: None', + '', + ' a member having mangled-like name', + '', + '', + ' .. py:attribute:: Bar.__address', + ' :module: target.name_mangling', + ' :value: None', + '', + '', + '.. py:class:: Foo()', + ' :module: target.name_mangling', + '', + '', + ' .. py:attribute:: Foo.__age', + ' :module: target.name_mangling', + ' :value: None', + '', + '', + ' .. py:attribute:: Foo.__name', + ' :module: target.name_mangling', + ' :value: None', + '', + ' name of Foo', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_hide_value(app): + options = {'members': True} + actual = do_autodoc(app, 'module', 'target.hide_value', options) + assert list(actual) == [ + '', + '.. py:module:: target.hide_value', + '', + '', + '.. py:class:: Foo()', + ' :module: target.hide_value', + '', + ' docstring', + '', + '', + ' .. py:attribute:: Foo.SENTINEL1', + ' :module: target.hide_value', + '', + ' docstring', + '', + ' :meta hide-value:', + '', + '', + ' .. py:attribute:: Foo.SENTINEL2', + ' :module: target.hide_value', + '', + ' :meta hide-value:', + '', + '', + '.. py:data:: SENTINEL1', + ' :module: target.hide_value', + '', + ' docstring', + '', + ' :meta hide-value:', + '', + '', + '.. py:data:: SENTINEL2', + ' :module: target.hide_value', + '', + ' :meta hide-value:', + '', + ] diff --git a/tests/test_ext_autodoc_autoattribute.py b/tests/test_ext_autodoc_autoattribute.py new file mode 100644 index 000000000..48e897b2e --- /dev/null +++ b/tests/test_ext_autodoc_autoattribute.py @@ -0,0 +1,217 @@ +""" + test_ext_autodoc_autoattribute + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Test the autodoc extension. This tests mainly the Documenters; the auto + directives are tested in a test source file translated by test_build. + + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import sys + +import pytest + +from .test_ext_autodoc import do_autodoc + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute(app): + actual = do_autodoc(app, 'attribute', 'target.Class.attr') + assert list(actual) == [ + '', + '.. py:attribute:: Class.attr', + ' :module: target', + " :value: 'bar'", + '', + ' should be documented -- süß', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_novalue(app): + options = {'no-value': True} + actual = do_autodoc(app, 'attribute', 'target.Class.attr', options) + assert list(actual) == [ + '', + '.. py:attribute:: Class.attr', + ' :module: target', + '', + ' should be documented -- süß', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_typed_variable(app): + actual = do_autodoc(app, 'attribute', 'target.typed_vars.Class.attr2') + assert list(actual) == [ + '', + '.. py:attribute:: Class.attr2', + ' :module: target.typed_vars', + ' :type: int', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_typed_variable_in_alias(app): + actual = do_autodoc(app, 'attribute', 'target.typed_vars.Alias.attr2') + assert list(actual) == [ + '', + '.. py:attribute:: Alias.attr2', + ' :module: target.typed_vars', + ' :type: int', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_instance_variable(app): + actual = do_autodoc(app, 'attribute', 'target.typed_vars.Class.attr4') + assert list(actual) == [ + '', + '.. py:attribute:: Class.attr4', + ' :module: target.typed_vars', + ' :type: int', + '', + ' attr4', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_instance_variable_in_alias(app): + actual = do_autodoc(app, 'attribute', 'target.typed_vars.Alias.attr4') + assert list(actual) == [ + '', + '.. py:attribute:: Alias.attr4', + ' :module: target.typed_vars', + ' :type: int', + '', + ' attr4', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_slots_variable_list(app): + actual = do_autodoc(app, 'attribute', 'target.slots.Foo.attr') + assert list(actual) == [ + '', + '.. py:attribute:: Foo.attr', + ' :module: target.slots', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_slots_variable_dict(app): + actual = do_autodoc(app, 'attribute', 'target.slots.Bar.attr1') + assert list(actual) == [ + '', + '.. py:attribute:: Bar.attr1', + ' :module: target.slots', + '', + ' docstring of attr1', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_slots_variable_str(app): + actual = do_autodoc(app, 'attribute', 'target.slots.Baz.attr') + assert list(actual) == [ + '', + '.. py:attribute:: Baz.attr', + ' :module: target.slots', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_GenericAlias(app): + actual = do_autodoc(app, 'attribute', 'target.genericalias.Class.T') + if sys.version_info < (3, 7): + assert list(actual) == [ + '', + '.. py:attribute:: Class.T', + ' :module: target.genericalias', + ' :value: typing.List[int]', + '', + ' A list of int', + '', + ] + else: + assert list(actual) == [ + '', + '.. py:attribute:: Class.T', + ' :module: target.genericalias', + '', + ' A list of int', + '', + ' alias of List[int]', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_NewType(app): + actual = do_autodoc(app, 'attribute', 'target.typevar.Class.T6') + assert list(actual) == [ + '', + '.. py:attribute:: Class.T6', + ' :module: target.typevar', + '', + ' T6', + '', + ' alias of :class:`int`', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_TypeVar(app): + actual = do_autodoc(app, 'attribute', 'target.typevar.Class.T1') + assert list(actual) == [ + '', + '.. py:attribute:: Class.T1', + ' :module: target.typevar', + '', + ' T1', + '', + " alias of TypeVar('T1')", + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_hide_value(app): + actual = do_autodoc(app, 'attribute', 'target.hide_value.Foo.SENTINEL1') + assert list(actual) == [ + '', + '.. py:attribute:: Foo.SENTINEL1', + ' :module: target.hide_value', + '', + ' docstring', + '', + ' :meta hide-value:', + '', + ] + + actual = do_autodoc(app, 'attribute', 'target.hide_value.Foo.SENTINEL2') + assert list(actual) == [ + '', + '.. py:attribute:: Foo.SENTINEL2', + ' :module: target.hide_value', + '', + ' :meta hide-value:', + '', + ] diff --git a/tests/test_ext_autodoc_autoclass.py b/tests/test_ext_autodoc_autoclass.py new file mode 100644 index 000000000..488b72263 --- /dev/null +++ b/tests/test_ext_autodoc_autoclass.py @@ -0,0 +1,193 @@ +""" + test_ext_autodoc_autoclass + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Test the autodoc extension. This tests mainly the Documenters; the auto + directives are tested in a test source file translated by test_build. + + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import sys + +import pytest + +from .test_ext_autodoc import do_autodoc + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_classes(app): + actual = do_autodoc(app, 'function', 'target.classes.Foo') + assert list(actual) == [ + '', + '.. py:function:: Foo()', + ' :module: target.classes', + '', + ] + + actual = do_autodoc(app, 'function', 'target.classes.Bar') + assert list(actual) == [ + '', + '.. py:function:: Bar(x, y)', + ' :module: target.classes', + '', + ] + + actual = do_autodoc(app, 'function', 'target.classes.Baz') + assert list(actual) == [ + '', + '.. py:function:: Baz(x, y)', + ' :module: target.classes', + '', + ] + + actual = do_autodoc(app, 'function', 'target.classes.Qux') + assert list(actual) == [ + '', + '.. py:function:: Qux(foo, bar)', + ' :module: target.classes', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_instance_variable(app): + options = {'members': True} + actual = do_autodoc(app, 'class', 'target.instance_variable.Bar', options) + assert list(actual) == [ + '', + '.. py:class:: Bar()', + ' :module: target.instance_variable', + '', + '', + ' .. py:attribute:: Bar.attr2', + ' :module: target.instance_variable', + '', + ' docstring bar', + '', + '', + ' .. py:attribute:: Bar.attr3', + ' :module: target.instance_variable', + '', + ' docstring bar', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_inherited_instance_variable(app): + options = {'members': True, + 'inherited-members': True} + actual = do_autodoc(app, 'class', 'target.instance_variable.Bar', options) + assert list(actual) == [ + '', + '.. py:class:: Bar()', + ' :module: target.instance_variable', + '', + '', + ' .. py:attribute:: Bar.attr1', + ' :module: target.instance_variable', + '', + ' docstring foo', + '', + '', + ' .. py:attribute:: Bar.attr2', + ' :module: target.instance_variable', + '', + ' docstring bar', + '', + '', + ' .. py:attribute:: Bar.attr3', + ' :module: target.instance_variable', + '', + ' docstring bar', + '', + ] + + +def test_decorators(app): + actual = do_autodoc(app, 'class', 'target.decorator.Baz') + assert list(actual) == [ + '', + '.. py:class:: Baz(name=None, age=None)', + ' :module: target.decorator', + '', + ] + + actual = do_autodoc(app, 'class', 'target.decorator.Qux') + assert list(actual) == [ + '', + '.. py:class:: Qux(name=None, age=None)', + ' :module: target.decorator', + '', + ] + + actual = do_autodoc(app, 'class', 'target.decorator.Quux') + assert list(actual) == [ + '', + '.. py:class:: Quux(name=None, age=None)', + ' :module: target.decorator', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_slots_attribute(app): + options = {"members": None} + actual = do_autodoc(app, 'class', 'target.slots.Bar', options) + assert list(actual) == [ + '', + '.. py:class:: Bar()', + ' :module: target.slots', + '', + ' docstring', + '', + '', + ' .. py:attribute:: Bar.attr1', + ' :module: target.slots', + '', + ' docstring of attr1', + '', + '', + ' .. py:attribute:: Bar.attr2', + ' :module: target.slots', + '', + ' docstring of instance attr2', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_show_inheritance_for_subclass_of_generic_type(app): + options = {'show-inheritance': True} + actual = do_autodoc(app, 'class', 'target.classes.Quux', options) + assert list(actual) == [ + '', + '.. py:class:: Quux(iterable=(), /)', + ' :module: target.classes', + '', + ' Bases: :class:`List`\\ [:obj:`Union`\\ [:class:`int`, :class:`float`]]', + '', + ' A subclass of List[Union[int, float]]', + '', + ] + + +def test_class_alias(app): + def autodoc_process_docstring(*args): + """A handler always raises an error. + This confirms this handler is never called for class aliases. + """ + raise + + app.connect('autodoc-process-docstring', autodoc_process_docstring) + actual = do_autodoc(app, 'class', 'target.classes.Alias') + assert list(actual) == [ + '', + '.. py:attribute:: Alias', + ' :module: target.classes', + '', + ' alias of :class:`target.classes.Foo`', + ] diff --git a/tests/test_ext_autodoc_autodata.py b/tests/test_ext_autodoc_autodata.py new file mode 100644 index 000000000..907d70aa1 --- /dev/null +++ b/tests/test_ext_autodoc_autodata.py @@ -0,0 +1,157 @@ +""" + test_ext_autodoc_autodata + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Test the autodoc extension. This tests mainly the Documenters; the auto + directives are tested in a test source file translated by test_build. + + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import sys + +import pytest + +from .test_ext_autodoc import do_autodoc + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodata(app): + actual = do_autodoc(app, 'data', 'target.integer') + assert list(actual) == [ + '', + '.. py:data:: integer', + ' :module: target', + ' :value: 1', + '', + ' documentation for the integer', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodata_novalue(app): + options = {'no-value': True} + actual = do_autodoc(app, 'data', 'target.integer', options) + assert list(actual) == [ + '', + '.. py:data:: integer', + ' :module: target', + '', + ' documentation for the integer', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodata_typed_variable(app): + actual = do_autodoc(app, 'data', 'target.typed_vars.attr2') + assert list(actual) == [ + '', + '.. py:data:: attr2', + ' :module: target.typed_vars', + ' :type: str', + '', + ' attr2', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodata_type_comment(app): + actual = do_autodoc(app, 'data', 'target.typed_vars.attr3') + assert list(actual) == [ + '', + '.. py:data:: attr3', + ' :module: target.typed_vars', + ' :type: str', + " :value: ''", + '', + ' attr3', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodata_GenericAlias(app): + actual = do_autodoc(app, 'data', 'target.genericalias.T') + if sys.version_info < (3, 7): + assert list(actual) == [ + '', + '.. py:data:: T', + ' :module: target.genericalias', + ' :value: typing.List[int]', + '', + ' A list of int', + '', + ] + else: + assert list(actual) == [ + '', + '.. py:data:: T', + ' :module: target.genericalias', + '', + ' A list of int', + '', + ' alias of List[int]', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodata_NewType(app): + actual = do_autodoc(app, 'data', 'target.typevar.T6') + assert list(actual) == [ + '', + '.. py:data:: T6', + ' :module: target.typevar', + '', + ' T6', + '', + ' alias of :class:`int`', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodata_TypeVar(app): + actual = do_autodoc(app, 'data', 'target.typevar.T1') + assert list(actual) == [ + '', + '.. py:data:: T1', + ' :module: target.typevar', + '', + ' T1', + '', + " alias of TypeVar('T1')", + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodata_hide_value(app): + actual = do_autodoc(app, 'data', 'target.hide_value.SENTINEL1') + assert list(actual) == [ + '', + '.. py:data:: SENTINEL1', + ' :module: target.hide_value', + '', + ' docstring', + '', + ' :meta hide-value:', + '', + ] + + actual = do_autodoc(app, 'data', 'target.hide_value.SENTINEL2') + assert list(actual) == [ + '', + '.. py:data:: SENTINEL2', + ' :module: target.hide_value', + '', + ' :meta hide-value:', + '', + ] diff --git a/tests/test_ext_autodoc_autofunction.py b/tests/test_ext_autodoc_autofunction.py index b4be85019..aa0476687 100644 --- a/tests/test_ext_autodoc_autofunction.py +++ b/tests/test_ext_autodoc_autofunction.py @@ -5,13 +5,15 @@ Test the autodoc extension. This tests mainly the Documenters; the auto directives are tested in a test source file translated by test_build. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import sys + import pytest -from test_ext_autodoc import do_autodoc +from .test_ext_autodoc import do_autodoc @pytest.mark.sphinx('html', testroot='ext-autodoc') @@ -40,6 +42,14 @@ def test_classes(app): '', ] + actual = do_autodoc(app, 'function', 'target.classes.Qux') + assert list(actual) == [ + '', + '.. py:function:: Qux(foo, bar)', + ' :module: target.classes', + '', + ] + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_callable(app): @@ -85,8 +95,8 @@ def test_methoddescriptor(app): actual = do_autodoc(app, 'function', 'builtins.int.__add__') assert list(actual) == [ '', - '.. py:function:: int.__add__(self, value, /)', - ' :module: builtins', + '.. py:function:: __add__(self, value, /)', + ' :module: builtins.int', '', ' Return self+value.', '', @@ -98,7 +108,7 @@ def test_decorated(app): actual = do_autodoc(app, 'function', 'target.decorator.foo') assert list(actual) == [ '', - '.. py:function:: foo()', + '.. py:function:: foo(name=None, age=None)', ' :module: target.decorator', '', ] @@ -108,16 +118,23 @@ def test_decorated(app): def test_singledispatch(app): options = {} actual = do_autodoc(app, 'function', 'target.singledispatch.func', options) - assert list(actual) == [ - '', - '.. py:function:: func(arg, kwarg=None)', - ' func(arg: int, kwarg=None)', - ' func(arg: str, kwarg=None)', - ' :module: target.singledispatch', - '', - ' A function for general use.', - '', - ] + if sys.version_info < (3, 6): + # check the result via "in" because the order of singledispatch signatures is + # usually changed (because dict is not OrderedDict yet!) + assert '.. py:function:: func(arg, kwarg=None)' in actual + assert ' func(arg: int, kwarg=None)' in actual + assert ' func(arg: str, kwarg=None)' in actual + else: + assert list(actual) == [ + '', + '.. py:function:: func(arg, kwarg=None)', + ' func(arg: int, kwarg=None)', + ' func(arg: str, kwarg=None)', + ' :module: target.singledispatch', + '', + ' A function for general use.', + '', + ] @pytest.mark.sphinx('html', testroot='ext-autodoc') @@ -146,3 +163,16 @@ def test_wrapped_function(app): ' This function is slow.', '', ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_wrapped_function_contextmanager(app): + actual = do_autodoc(app, 'function', 'target.wrappedfunction.feeling_good') + assert list(actual) == [ + '', + '.. py:function:: feeling_good(x: int, y: int) -> Generator', + ' :module: target.wrappedfunction', + '', + " You'll feel better in this context!", + '', + ] diff --git a/tests/test_ext_autodoc_automodule.py b/tests/test_ext_autodoc_automodule.py new file mode 100644 index 000000000..df57724b3 --- /dev/null +++ b/tests/test_ext_autodoc_automodule.py @@ -0,0 +1,44 @@ +""" + test_ext_autodoc_autocmodule + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Test the autodoc extension. This tests mainly the Documenters; the auto + directives are tested in a test source file translated by test_build. + + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import sys + +import pytest + +from .test_ext_autodoc import do_autodoc + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_empty_all(app): + options = {'members': True} + actual = do_autodoc(app, 'module', 'target.empty_all', options) + assert list(actual) == [ + '', + '.. py:module:: target.empty_all', + '', + 'docsting of empty_all module.', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc', + confoverrides={'autodoc_mock_imports': ['missing_module', + 'missing_package1', + 'missing_package2', + 'missing_package3', + 'sphinx.missing_module4']}) +@pytest.mark.usefixtures("rollback_sysmodules") +def test_subclass_of_mocked_object(app): + sys.modules.pop('target', None) # unload target module to clear the module cache + + options = {'members': True} + actual = do_autodoc(app, 'module', 'target.need_mocks', options) + assert '.. py:class:: Inherited(*args: Any, **kwargs: Any)' in actual diff --git a/tests/test_ext_autodoc_configs.py b/tests/test_ext_autodoc_configs.py index 674620df0..bae684397 100644 --- a/tests/test_ext_autodoc_configs.py +++ b/tests/test_ext_autodoc_configs.py @@ -4,7 +4,7 @@ Test the autodoc extension. This tests mainly for config variables - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,7 +13,9 @@ import sys import pytest -from test_ext_autodoc import do_autodoc +from sphinx.testing import restructuredtext + +from .test_ext_autodoc import do_autodoc IS_PYPY = platform.python_implementation() == 'PyPy' @@ -427,7 +429,10 @@ def test_autoclass_content_and_docstring_signature_both(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') +@pytest.mark.usefixtures("rollback_sysmodules") def test_mocked_module_imports(app, warning): + sys.modules.pop('target', None) # unload target module to clear the module cache + # no autodoc_mock_imports options = {"members": 'TestAutodoc,decoratedFunction,func'} actual = do_autodoc(app, 'module', 'target.need_mocks', options) @@ -488,7 +493,7 @@ def test_autodoc_typehints_signature(app): '.. py:module:: target.typehints', '', '', - '.. py:class:: Math(s: str, o: object = None)', + '.. py:class:: Math(s: str, o: Optional[Any] = None)', ' :module: target.typehints', '', '', @@ -608,6 +613,54 @@ def test_autodoc_typehints_none(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc', + confoverrides={'autodoc_typehints': 'none'}) +def test_autodoc_typehints_none_for_overload(app): + options = {"members": None} + actual = do_autodoc(app, 'module', 'target.overload', options) + assert list(actual) == [ + '', + '.. py:module:: target.overload', + '', + '', + '.. py:class:: Bar(x, y)', + ' :module: target.overload', + '', + ' docstring', + '', + '', + '.. py:class:: Baz(x, y)', + ' :module: target.overload', + '', + ' docstring', + '', + '', + '.. py:class:: Foo(x, y)', + ' :module: target.overload', + '', + ' docstring', + '', + '', + '.. py:class:: Math()', + ' :module: target.overload', + '', + ' docstring', + '', + '', + ' .. py:method:: Math.sum(x, y=None)', + ' :module: target.overload', + '', + ' docstring', + '', + '', + '.. py:function:: sum(x, y=None)', + ' :module: target.overload', + '', + ' docstring', + '', + ] + + @pytest.mark.sphinx('text', testroot='ext-autodoc', confoverrides={'autodoc_typehints': "description"}) def test_autodoc_typehints_description(app): @@ -633,11 +686,157 @@ def test_autodoc_typehints_description(app): in context) +@pytest.mark.sphinx('text', testroot='ext-autodoc', + confoverrides={'autodoc_typehints': "description"}) +def test_autodoc_typehints_description_for_invalid_node(app): + text = ".. py:function:: hello; world" + restructuredtext.parse(app, text) # raises no error + + +@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.') +@pytest.mark.sphinx('text', testroot='ext-autodoc') +def test_autodoc_type_aliases(app): + # default + options = {"members": None} + actual = do_autodoc(app, 'module', 'target.annotations', options) + assert list(actual) == [ + '', + '.. py:module:: target.annotations', + '', + '', + '.. py:class:: Foo()', + ' :module: target.annotations', + '', + ' docstring', + '', + '', + ' .. py:attribute:: Foo.attr1', + ' :module: target.annotations', + ' :type: int', + '', + ' docstring', + '', + '', + ' .. py:attribute:: Foo.attr2', + ' :module: target.annotations', + ' :type: int', + '', + ' docstring', + '', + '', + '.. py:function:: mult(x: int, y: int) -> int', + ' mult(x: float, y: float) -> float', + ' :module: target.annotations', + '', + ' docstring', + '', + '', + '.. py:function:: sum(x: int, y: int) -> int', + ' :module: target.annotations', + '', + ' docstring', + '', + '', + '.. py:data:: variable', + ' :module: target.annotations', + ' :type: int', + '', + ' docstring', + '', + '', + '.. py:data:: variable2', + ' :module: target.annotations', + ' :type: int', + ' :value: None', + '', + ' docstring', + '', + ] + + # define aliases + app.config.autodoc_type_aliases = {'myint': 'myint'} + actual = do_autodoc(app, 'module', 'target.annotations', options) + assert list(actual) == [ + '', + '.. py:module:: target.annotations', + '', + '', + '.. py:class:: Foo()', + ' :module: target.annotations', + '', + ' docstring', + '', + '', + ' .. py:attribute:: Foo.attr1', + ' :module: target.annotations', + ' :type: myint', + '', + ' docstring', + '', + '', + ' .. py:attribute:: Foo.attr2', + ' :module: target.annotations', + ' :type: myint', + '', + ' docstring', + '', + '', + '.. py:function:: mult(x: myint, y: myint) -> myint', + ' mult(x: float, y: float) -> float', + ' :module: target.annotations', + '', + ' docstring', + '', + '', + '.. py:function:: sum(x: myint, y: myint) -> myint', + ' :module: target.annotations', + '', + ' docstring', + '', + '', + '.. py:data:: variable', + ' :module: target.annotations', + ' :type: myint', + '', + ' docstring', + '', + '', + '.. py:data:: variable2', + ' :module: target.annotations', + ' :type: myint', + ' :value: None', + '', + ' docstring', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.') +@pytest.mark.sphinx('text', testroot='ext-autodoc', + srcdir='autodoc_typehints_description_and_type_aliases', + confoverrides={'autodoc_typehints': "description", + 'autodoc_type_aliases': {'myint': 'myint'}}) +def test_autodoc_typehints_description_and_type_aliases(app): + (app.srcdir / 'annotations.rst').write_text('.. autofunction:: target.annotations.sum') + app.build() + context = (app.outdir / 'annotations.txt').read_text() + assert ('target.annotations.sum(x, y)\n' + '\n' + ' docstring\n' + '\n' + ' Parameters:\n' + ' * **x** (*myint*) --\n' + '\n' + ' * **y** (*myint*) --\n' + '\n' + ' Return type:\n' + ' myint\n' == context) + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_default_options(app): # no settings - actual = do_autodoc(app, 'class', 'target.enum.EnumCls') + actual = do_autodoc(app, 'class', 'target.enums.EnumCls') assert ' .. py:attribute:: EnumCls.val1' not in actual assert ' .. py:attribute:: EnumCls.val4' not in actual actual = do_autodoc(app, 'class', 'target.CustomIter') @@ -647,13 +846,13 @@ def test_autodoc_default_options(app): # with :members: app.config.autodoc_default_options = {'members': None} - actual = do_autodoc(app, 'class', 'target.enum.EnumCls') + actual = do_autodoc(app, 'class', 'target.enums.EnumCls') assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val4' not in actual # with :members: = True app.config.autodoc_default_options = {'members': True} - actual = do_autodoc(app, 'class', 'target.enum.EnumCls') + actual = do_autodoc(app, 'class', 'target.enums.EnumCls') assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val4' not in actual @@ -662,7 +861,7 @@ def test_autodoc_default_options(app): 'members': None, 'undoc-members': None, } - actual = do_autodoc(app, 'class', 'target.enum.EnumCls') + actual = do_autodoc(app, 'class', 'target.enums.EnumCls') assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val4' in actual @@ -688,7 +887,7 @@ def test_autodoc_default_options(app): 'members': None, 'exclude-members': None, } - actual = do_autodoc(app, 'class', 'target.enum.EnumCls') + actual = do_autodoc(app, 'class', 'target.enums.EnumCls') assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val4' not in actual app.config.autodoc_default_options = { @@ -712,7 +911,7 @@ def test_autodoc_default_options(app): def test_autodoc_default_options_with_values(app): # with :members: app.config.autodoc_default_options = {'members': 'val1,val2'} - actual = do_autodoc(app, 'class', 'target.enum.EnumCls') + actual = do_autodoc(app, 'class', 'target.enums.EnumCls') assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val2' in actual assert ' .. py:attribute:: EnumCls.val3' not in actual @@ -757,7 +956,7 @@ def test_autodoc_default_options_with_values(app): 'members': None, 'exclude-members': 'val1' } - actual = do_autodoc(app, 'class', 'target.enum.EnumCls') + actual = do_autodoc(app, 'class', 'target.enums.EnumCls') assert ' .. py:attribute:: EnumCls.val1' not in actual assert ' .. py:attribute:: EnumCls.val2' in actual assert ' .. py:attribute:: EnumCls.val3' in actual diff --git a/tests/test_ext_autodoc_events.py b/tests/test_ext_autodoc_events.py index 4e8348abc..561ac49de 100644 --- a/tests/test_ext_autodoc_events.py +++ b/tests/test_ext_autodoc_events.py @@ -4,14 +4,15 @@ Test the autodoc extension. This tests mainly for autodoc events - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest from sphinx.ext.autodoc import between, cut_lines -from test_ext_autodoc import do_autodoc + +from .test_ext_autodoc import do_autodoc @pytest.mark.sphinx('html', testroot='ext-autodoc') @@ -28,7 +29,25 @@ def test_process_docstring(app): '.. py:function:: func()', ' :module: target.process_docstring', '', - ' my docstring' + ' my docstring', + '', + ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_process_docstring_for_nondatadescriptor(app): + def on_process_docstring(app, what, name, obj, options, lines): + raise + + app.connect('autodoc-process-docstring', on_process_docstring) + + actual = do_autodoc(app, 'attribute', 'target.AttCls.a1') + assert list(actual) == [ + '', + '.. py:attribute:: AttCls.a1', + ' :module: target', + ' :value: hello world', + '', ] @@ -79,3 +98,28 @@ def test_between_exclude(app): ' third line', '', ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_skip_module_member(app): + def autodoc_skip_member(app, what, name, obj, skip, options): + if name == "Class": + return True # Skip "Class" class in __all__ + elif name == "raises": + return False # Show "raises()" function (not in __all__) + + app.connect('autodoc-skip-member', autodoc_skip_member) + + options = {"members": None} + actual = do_autodoc(app, 'module', 'target', options) + assert list(actual) == [ + '', + '.. py:module:: target', + '', + '', + '.. py:function:: raises(exc, func, *args, **kwds)', + ' :module: target', + '', + ' Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*.', + '', + ] diff --git a/tests/test_ext_autodoc_mock.py b/tests/test_ext_autodoc_mock.py index 4760493cf..08157ac45 100644 --- a/tests/test_ext_autodoc_mock.py +++ b/tests/test_ext_autodoc_mock.py @@ -4,17 +4,18 @@ Test the autodoc extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import abc import sys from importlib import import_module +from typing import TypeVar import pytest -from sphinx.ext.autodoc.mock import _MockModule, _MockObject, mock +from sphinx.ext.autodoc.mock import _MockModule, _MockObject, ismock, mock def test_MockModule(): @@ -39,6 +40,7 @@ def test_MockObject(): assert isinstance(mock.attr1.attr2, _MockObject) assert isinstance(mock.attr1.attr2.meth(), _MockObject) + # subclassing class SubClass(mock.SomeClass): """docstring of SubClass""" @@ -51,6 +53,16 @@ def test_MockObject(): assert obj.method() == "string" assert isinstance(obj.other_method(), SubClass) + # parametrized type + T = TypeVar('T') + + class SubClass2(mock.SomeClass[T]): + """docstring of SubClass""" + + obj2 = SubClass2() + assert SubClass2.__doc__ == "docstring of SubClass" + assert isinstance(obj2, SubClass2) + def test_mock(): modname = 'sphinx.unknown' @@ -117,3 +129,19 @@ def test_mock_decorator(): assert func.__doc__ == "docstring" assert Foo.meth.__doc__ == "docstring" assert Bar.__doc__ == "docstring" + + +def test_ismock(): + with mock(['sphinx.unknown']): + mod1 = import_module('sphinx.unknown') + mod2 = import_module('sphinx.application') + + class Inherited(mod1.Class): + pass + + assert ismock(mod1) is True + assert ismock(mod1.Class) is True + assert ismock(Inherited) is False + + assert ismock(mod2) is False + assert ismock(mod2.Sphinx) is False diff --git a/tests/test_ext_autodoc_private_members.py b/tests/test_ext_autodoc_private_members.py index f4cadd3a5..0de74b898 100644 --- a/tests/test_ext_autodoc_private_members.py +++ b/tests/test_ext_autodoc_private_members.py @@ -4,13 +4,13 @@ Test the autodoc extension. This tests mainly for private-members option. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest -from test_ext_autodoc import do_autodoc +from .test_ext_autodoc import do_autodoc @pytest.mark.sphinx('html', testroot='ext-autodoc') @@ -23,6 +23,13 @@ def test_private_field(app): '.. py:module:: target.private', '', '', + '.. py:data:: _PUBLIC_CONSTANT', + ' :module: target.private', + ' :value: None', + '', + ' :meta public:', + '', + '', '.. py:function:: _public_function(name)', ' :module: target.private', '', @@ -44,6 +51,20 @@ def test_private_field_and_private_members(app): '.. py:module:: target.private', '', '', + '.. py:data:: PRIVATE_CONSTANT', + ' :module: target.private', + ' :value: None', + '', + ' :meta private:', + '', + '', + '.. py:data:: _PUBLIC_CONSTANT', + ' :module: target.private', + ' :value: None', + '', + ' :meta public:', + '', + '', '.. py:function:: _public_function(name)', ' :module: target.private', '', @@ -60,3 +81,31 @@ def test_private_field_and_private_members(app): ' :meta private:', '', ] + + +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_private_members(app): + app.config.autoclass_content = 'class' + options = {"members": None, + "private-members": "_PUBLIC_CONSTANT,_public_function"} + actual = do_autodoc(app, 'module', 'target.private', options) + assert list(actual) == [ + '', + '.. py:module:: target.private', + '', + '', + '.. py:data:: _PUBLIC_CONSTANT', + ' :module: target.private', + ' :value: None', + '', + ' :meta public:', + '', + '', + '.. py:function:: _public_function(name)', + ' :module: target.private', + '', + ' public_function is a docstring().', + '', + ' :meta public:', + '', + ] diff --git a/tests/test_ext_autosectionlabel.py b/tests/test_ext_autosectionlabel.py index 310435d8e..0afe13b41 100644 --- a/tests/test_ext_autosectionlabel.py +++ b/tests/test_ext_autosectionlabel.py @@ -4,7 +4,7 @@ Test sphinx.ext.autosectionlabel extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index a65826141..da7c53ec9 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -4,7 +4,7 @@ Test the autosummary extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -16,13 +16,11 @@ import pytest from docutils import nodes from sphinx import addnodes -from sphinx.ext.autosummary import ( - autosummary_table, autosummary_toc, mangle_signature, import_by_name, extract_summary -) -from sphinx.ext.autosummary.generate import ( - AutosummaryEntry, generate_autosummary_content, generate_autosummary_docs, - main as autogen_main -) +from sphinx.ext.autosummary import (autosummary_table, autosummary_toc, extract_summary, + import_by_name, mangle_signature) +from sphinx.ext.autosummary.generate import (AutosummaryEntry, generate_autosummary_content, + generate_autosummary_docs) +from sphinx.ext.autosummary.generate import main as autogen_main from sphinx.testing.util import assert_node, etree_parse from sphinx.util.docutils import new_document from sphinx.util.osutil import cd @@ -97,7 +95,10 @@ def test_extract_summary(capsys): # abbreviations doc = ['Blabla, i.e. bla.'] - assert extract_summary(doc, document) == 'Blabla, i.e.' + assert extract_summary(doc, document) == ' '.join(doc) + + doc = ['Blabla, et al. bla.'] + assert extract_summary(doc, document) == ' '.join(doc) # literal doc = ['blah blah::'] @@ -108,6 +109,12 @@ def test_extract_summary(capsys): '========='] assert extract_summary(doc, document) == 'blah blah' + # hyperlink target + doc = ['Do `this <https://www.sphinx-doc.org/>`_ and that. ' + 'blah blah blah.'] + assert (extract_summary(doc, document) == + 'Do `this <https://www.sphinx-doc.org/>`_ and that.') + _, err = capsys.readouterr() assert err == '' @@ -202,17 +209,17 @@ def test_autosummary_generate_content_for_module(app): assert template.render.call_args[0][0] == 'module' context = template.render.call_args[0][1] - assert context['members'] == ['Exc', 'Foo', '_Baz', '_Exc', '__builtins__', - '__cached__', '__doc__', '__file__', '__name__', - '__package__', '_quux', 'bar', 'qux'] + assert context['members'] == ['CONSTANT1', 'CONSTANT2', 'Exc', 'Foo', '_Baz', '_Exc', + '__builtins__', '__cached__', '__doc__', '__file__', + '__name__', '__package__', '_quux', 'bar', 'qux'] assert context['functions'] == ['bar'] assert context['all_functions'] == ['_quux', 'bar'] assert context['classes'] == ['Foo'] assert context['all_classes'] == ['Foo', '_Baz'] assert context['exceptions'] == ['Exc'] assert context['all_exceptions'] == ['Exc', '_Exc'] - assert context['attributes'] == ['qux'] - assert context['all_attributes'] == ['qux'] + assert context['attributes'] == ['CONSTANT1', 'qux'] + assert context['all_attributes'] == ['CONSTANT1', 'qux'] assert context['fullname'] == 'autosummary_dummy_module' assert context['module'] == 'autosummary_dummy_module' assert context['objname'] == '' @@ -233,8 +240,9 @@ def test_autosummary_generate_content_for_module_skipped(app): generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None, template, None, False, app, False, {}) context = template.render.call_args[0][1] - assert context['members'] == ['_Baz', '_Exc', '__builtins__', '__cached__', '__doc__', - '__file__', '__name__', '__package__', '_quux', 'qux'] + assert context['members'] == ['CONSTANT1', 'CONSTANT2', '_Baz', '_Exc', '__builtins__', + '__cached__', '__doc__', '__file__', '__name__', + '__package__', '_quux', 'qux'] assert context['functions'] == [] assert context['classes'] == [] assert context['exceptions'] == [] @@ -250,18 +258,18 @@ def test_autosummary_generate_content_for_module_imported_members(app): assert template.render.call_args[0][0] == 'module' context = template.render.call_args[0][1] - assert context['members'] == ['Exc', 'Foo', 'Union', '_Baz', '_Exc', '__builtins__', - '__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__spec__', '_quux', - 'bar', 'path', 'qux'] + assert context['members'] == ['CONSTANT1', 'CONSTANT2', 'Exc', 'Foo', 'Union', '_Baz', + '_Exc', '__builtins__', '__cached__', '__doc__', + '__file__', '__loader__', '__name__', '__package__', + '__spec__', '_quux', 'bar', 'path', 'qux'] assert context['functions'] == ['bar'] assert context['all_functions'] == ['_quux', 'bar'] assert context['classes'] == ['Foo'] assert context['all_classes'] == ['Foo', '_Baz'] assert context['exceptions'] == ['Exc'] assert context['all_exceptions'] == ['Exc', '_Exc'] - assert context['attributes'] == ['qux'] - assert context['all_attributes'] == ['qux'] + assert context['attributes'] == ['CONSTANT1', 'qux'] + assert context['all_attributes'] == ['CONSTANT1', 'qux'] assert context['fullname'] == 'autosummary_dummy_module' assert context['module'] == 'autosummary_dummy_module' assert context['objname'] == '' @@ -286,21 +294,28 @@ def test_autosummary_generate(app, status, warning): nodes.row, nodes.row, nodes.row, + nodes.row, nodes.row)])]) assert_node(doctree[4][0], addnodes.toctree, caption="An autosummary") - assert len(doctree[3][0][0][2]) == 5 + assert len(doctree[3][0][0][2]) == 6 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][2].astext() == 'autosummary_dummy_module.Foo.Bar()\n\n' - assert doctree[3][0][0][2][3].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n' - assert doctree[3][0][0][2][4].astext() == 'autosummary_dummy_module.qux\n\na module-level attribute' + assert doctree[3][0][0][2][3].astext() == 'autosummary_dummy_module.Foo.value\n\ndocstring' + assert doctree[3][0][0][2][4].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n' + assert doctree[3][0][0][2][5].astext() == 'autosummary_dummy_module.qux\n\na module-level attribute' module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text() assert (' .. autosummary::\n' ' \n' ' Foo\n' ' \n' in module) + assert (' .. autosummary::\n' + ' \n' + ' CONSTANT1\n' + ' qux\n' + ' \n' in module) Foo = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.rst').read_text() assert '.. automethod:: __init__' in Foo @@ -311,6 +326,8 @@ def test_autosummary_generate(app, status, warning): ' \n' in Foo) assert (' .. autosummary::\n' ' \n' + ' ~Foo.CONSTANT3\n' + ' ~Foo.CONSTANT4\n' ' ~Foo.baz\n' ' \n' in Foo) @@ -319,6 +336,11 @@ def test_autosummary_generate(app, status, warning): '\n' '.. autoclass:: Foo.Bar\n' in FooBar) + Foo_value = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.value.rst').read_text() + assert ('.. currentmodule:: autosummary_dummy_module\n' + '\n' + '.. autoattribute:: Foo.value' in Foo_value) + qux = (app.srcdir / 'generated' / 'autosummary_dummy_module.qux.rst').read_text() assert ('.. currentmodule:: autosummary_dummy_module\n' '\n' @@ -356,7 +378,10 @@ def test_autosummary_generate_overwrite2(app_params, make_app): @pytest.mark.sphinx('dummy', testroot='ext-autosummary-recursive') +@pytest.mark.usefixtures("rollback_sysmodules") def test_autosummary_recursive(app, status, warning): + sys.modules.pop('package', None) # unload target module to clear the module cache + app.build() # autosummary having :recursive: option @@ -380,6 +405,34 @@ def test_autosummary_recursive(app, status, warning): assert 'package.package.module' in content +@pytest.mark.sphinx('dummy', testroot='ext-autosummary-recursive', + srcdir='test_autosummary_recursive_skips_mocked_modules', + confoverrides={'autosummary_mock_imports': ['package.package']}) +@pytest.mark.usefixtures("rollback_sysmodules") +def test_autosummary_recursive_skips_mocked_modules(app, status, warning): + sys.modules.pop('package', None) # unload target module to clear the module cache + app.build() + + assert (app.srcdir / 'generated' / 'package.rst').exists() + assert (app.srcdir / 'generated' / 'package.module.rst').exists() + assert (app.srcdir / 'generated' / 'package.package.rst').exists() is False + assert (app.srcdir / 'generated' / 'package.package.module.rst').exists() is False + + +@pytest.mark.sphinx('dummy', testroot='ext-autosummary-filename-map') +def test_autosummary_filename_map(app, status, warning): + app.build() + + assert (app.srcdir / 'generated' / 'module_mangled.rst').exists() + assert not (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').exists() + assert (app.srcdir / 'generated' / 'bar.rst').exists() + assert not (app.srcdir / 'generated' / 'autosummary_dummy_module.bar.rst').exists() + assert (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.rst').exists() + + html_warnings = app._warning.getvalue() + assert html_warnings == '' + + @pytest.mark.sphinx('latex', **default_kw) def test_autosummary_latex_table_colspec(app, status, warning): app.builder.build_all() diff --git a/tests/test_ext_coverage.py b/tests/test_ext_coverage.py index 16f53112b..6172c502d 100644 --- a/tests/test_ext_coverage.py +++ b/tests/test_ext_coverage.py @@ -4,7 +4,7 @@ Test the coverage builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -28,6 +28,8 @@ def test_build(app, status, warning): assert ' * mod -- No module named mod' # in the "failed import" section + assert "undocumented py" not in status.getvalue() + c_undoc = (app.outdir / 'c.txt').read_text() assert c_undoc.startswith('Undocumented C API elements\n' '===========================\n') @@ -46,6 +48,8 @@ def test_build(app, status, warning): assert 'Class' in undoc_py['autodoc_target']['classes'] assert 'undocmeth' in undoc_py['autodoc_target']['classes']['Class'] + assert "undocumented c" not in status.getvalue() + @pytest.mark.sphinx('coverage', testroot='ext-coverage') def test_coverage_ignore_pyobjects(app, status, warning): @@ -64,3 +68,28 @@ Classes: ''' assert actual == expected + + +@pytest.mark.sphinx('coverage', confoverrides={'coverage_show_missing_items': True}) +def test_show_missing_items(app, status, warning): + app.builder.build_all() + + assert "undocumented" in status.getvalue() + + assert "py function raises" in status.getvalue() + assert "py class Base" in status.getvalue() + assert "py method Class.roger" in status.getvalue() + + assert "c api Py_SphinxTest [ function]" in status.getvalue() + + +@pytest.mark.sphinx('coverage', confoverrides={'coverage_show_missing_items': True}) +def test_show_missing_items_quiet(app, status, warning): + app.quiet = True + app.builder.build_all() + + assert "undocumented python function: autodoc_target :: raises" in warning.getvalue() + assert "undocumented python class: autodoc_target :: Base" in warning.getvalue() + assert "undocumented python method: autodoc_target :: Class :: roger" in warning.getvalue() + + assert "undocumented c api: Py_SphinxTest [function]" in warning.getvalue() diff --git a/tests/test_ext_doctest.py b/tests/test_ext_doctest.py index ebf7e19d3..729067b4d 100644 --- a/tests/test_ext_doctest.py +++ b/tests/test_ext_doctest.py @@ -4,14 +4,14 @@ Test the doctest extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os from collections import Counter -from docutils import nodes import pytest +from docutils import nodes from packaging.specifiers import InvalidSpecifier from packaging.version import InvalidVersion diff --git a/tests/test_ext_duration.py b/tests/test_ext_duration.py index 51b3e63aa..681530cef 100644 --- a/tests/test_ext_duration.py +++ b/tests/test_ext_duration.py @@ -4,11 +4,12 @@ Test sphinx.ext.duration extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re + import pytest diff --git a/tests/test_ext_githubpages.py b/tests/test_ext_githubpages.py index 41dbe4f60..5c13a8f97 100644 --- a/tests/test_ext_githubpages.py +++ b/tests/test_ext_githubpages.py @@ -4,7 +4,7 @@ Test sphinx.ext.githubpages extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_graphviz.py b/tests/test_ext_graphviz.py index a8de950ce..a19261e96 100644 --- a/tests/test_ext_graphviz.py +++ b/tests/test_ext_graphviz.py @@ -4,7 +4,7 @@ Test sphinx.ext.graphviz extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_ifconfig.py b/tests/test_ext_ifconfig.py index 232ddf0d8..eea2386c3 100644 --- a/tests/test_ext_ifconfig.py +++ b/tests/test_ext_ifconfig.py @@ -4,7 +4,7 @@ Test sphinx.ext.ifconfig extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_imgconverter.py b/tests/test_ext_imgconverter.py index 075446b0a..5f6f236cf 100644 --- a/tests/test_ext_imgconverter.py +++ b/tests/test_ext_imgconverter.py @@ -4,7 +4,7 @@ Test sphinx.ext.imgconverter extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_inheritance_diagram.py b/tests/test_ext_inheritance_diagram.py index 3125f2c6e..eada88e91 100644 --- a/tests/test_ext_inheritance_diagram.py +++ b/tests/test_ext_inheritance_diagram.py @@ -4,19 +4,18 @@ Test sphinx.ext.inheritance_diagram extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -import re import os +import re import sys import pytest -from sphinx.ext.inheritance_diagram import ( - InheritanceDiagram, InheritanceException, import_classes -) +from sphinx.ext.inheritance_diagram import (InheritanceDiagram, InheritanceException, + import_classes) @pytest.mark.sphinx(buildername="html", testroot="inheritance") @@ -109,7 +108,7 @@ def test_inheritance_diagram(app, status, warning): ('dummy.test.B', 'dummy.test.B', [], None) ] - # inheritance diagram with 2 top classes and specifiying the entire module + # inheritance diagram with 2 top classes and specifying the entire module # rendering should be # # A diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 53faa7a37..c4fddf029 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -4,27 +4,27 @@ Test the intersphinx extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import http.server import os import unittest -from io import BytesIO from unittest import mock import pytest -import requests from docutils import nodes -from test_util_inventory import inventory_v2, inventory_v2_not_having_version from sphinx import addnodes -from sphinx.ext.intersphinx import ( - load_mappings, missing_reference, normalize_intersphinx_mapping, _strip_basic_auth, - _get_safe_url, fetch_inventory, INVENTORY_FILENAME, inspect_main -) +from sphinx.ext.intersphinx import (INVENTORY_FILENAME, _get_safe_url, _strip_basic_auth, + fetch_inventory, inspect_main, load_mappings, + missing_reference, normalize_intersphinx_mapping) from sphinx.ext.intersphinx import setup as intersphinx_setup +from .test_util_inventory import inventory_v2, inventory_v2_not_having_version +from .utils import http_server + def fake_node(domain, type, target, content, **attrs): contnode = nodes.emphasis(content, content) @@ -46,7 +46,7 @@ def reference_check(app, *args, **kwds): @mock.patch('sphinx.ext.intersphinx._read_from_url') def test_fetch_inventory_redirection(_read_from_url, InventoryFile, app, status, warning): intersphinx_setup(app) - _read_from_url().readline.return_value = '# Sphinx inventory version 2'.encode() + _read_from_url().readline.return_value = b'# Sphinx inventory version 2' # same uri and inv, not redirected _read_from_url().url = 'http://hostname/' + INVENTORY_FILENAME @@ -433,24 +433,22 @@ def test_inspect_main_file(capsys, tempdir): assert stderr == "" -@mock.patch('requests.get') -def test_inspect_main_url(fake_get, capsys): +def test_inspect_main_url(capsys): """inspect_main interface, with url argument""" - raw = BytesIO(inventory_v2) - real_read = raw.read + class InventoryHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + self.send_response(200, "OK") + self.end_headers() + self.wfile.write(inventory_v2) - def fake_read(*args, **kwargs): - return real_read() + def log_message(*args, **kwargs): + # Silenced. + pass - raw.read = fake_read - url = 'http://hostname/' + INVENTORY_FILENAME - resp = requests.Response() - resp.status_code = 200 - resp.url = url - resp.raw = raw - fake_get.return_value = resp + url = 'http://localhost:7777/' + INVENTORY_FILENAME - inspect_main([url]) + with http_server(InventoryHandler): + inspect_main([url]) stdout, stderr = capsys.readouterr() assert stdout.startswith("c:function\n") diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py index 4df7d47c7..10c8c4866 100644 --- a/tests/test_ext_math.py +++ b/tests/test_ext_math.py @@ -4,7 +4,7 @@ Test math extensions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -15,6 +15,7 @@ import warnings import pytest from docutils import nodes +from sphinx.ext.mathjax import MATHJAX_URL from sphinx.testing.util import assert_node @@ -224,6 +225,18 @@ def test_mathjax_config(app, status, warning): '</script>' in content) +@pytest.mark.sphinx('html', testroot='ext-math', + confoverrides={'extensions': ['sphinx.ext.mathjax']}) +def test_mathjax_is_installed_only_if_document_having_math(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'index.html').read_text() + assert MATHJAX_URL in content + + content = (app.outdir / 'nomath.html').read_text() + assert MATHJAX_URL not in content + + @pytest.mark.sphinx('html', testroot='basic', confoverrides={'extensions': ['sphinx.ext.mathjax']}) def test_mathjax_is_not_installed_if_no_equations(app, status, warning): diff --git a/tests/test_ext_napoleon.py b/tests/test_ext_napoleon.py index eea0642f8..d6334b9eb 100644 --- a/tests/test_ext_napoleon.py +++ b/tests/test_ext_napoleon.py @@ -5,15 +5,17 @@ Tests for :mod:`sphinx.ext.napoleon.__init__` module. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import sys from collections import namedtuple from unittest import TestCase, mock from sphinx.application import Sphinx -from sphinx.ext.napoleon import _process_docstring, _skip_member, Config, setup +from sphinx.ext.napoleon import Config, _process_docstring, _skip_member, setup +from sphinx.testing.util import simple_decorator def _private_doc(): @@ -49,6 +51,11 @@ class SampleClass: def __special_undoc__(self): pass + @simple_decorator + def __decorated_func__(self): + """doc""" + pass + class SampleError(Exception): def _private_doc(self): @@ -129,16 +136,25 @@ class SkipMemberTest(TestCase): self.assertEqual(None, _skip_member(app, what, member, obj, skip, mock.Mock())) else: - self.assertFalse(_skip_member(app, what, member, obj, skip, - mock.Mock())) + self.assertIs(_skip_member(app, what, member, obj, skip, + mock.Mock()), False) setattr(app.config, config_name, False) self.assertEqual(None, _skip_member(app, what, member, obj, skip, mock.Mock())) def test_namedtuple(self): - self.assertSkip('class', '_asdict', - SampleNamedTuple._asdict, False, - 'napoleon_include_private_with_doc') + if sys.version_info < (3, 7): + self.assertSkip('class', '_asdict', + SampleNamedTuple._asdict, False, + 'napoleon_include_private_with_doc') + else: + # Since python 3.7, namedtuple._asdict() has not been documented + # because there is no way to check the method is a member of the + # namedtuple class. This testcase confirms only it does not + # raise an error on building document (refs: #1455) + self.assertSkip('class', '_asdict', + SampleNamedTuple._asdict, True, + 'napoleon_include_private_with_doc') def test_class_private_doc(self): self.assertSkip('class', '_private_doc', @@ -160,6 +176,11 @@ class SkipMemberTest(TestCase): SampleClass.__special_undoc__, True, 'napoleon_include_special_with_doc') + def test_class_decorated_doc(self): + self.assertSkip('class', '__decorated_func__', + SampleClass.__decorated_func__, False, + 'napoleon_include_special_with_doc') + def test_exception_private_doc(self): self.assertSkip('exception', '_private_doc', SampleError._private_doc, False, diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index 738fd6532..362e6fb8e 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -5,17 +5,28 @@ Tests for :mod:`sphinx.ext.napoleon.docstring` module. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import re +import sys from collections import namedtuple +from contextlib import contextmanager from inspect import cleandoc from textwrap import dedent from unittest import TestCase, mock +import pytest + from sphinx.ext.napoleon import Config -from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring +from sphinx.ext.napoleon.docstring import (GoogleDocstring, NumpyDocstring, + _convert_numpy_type_spec, _recombine_set_tokens, + _token_type, _tokenize_type_spec) + +if sys.version_info >= (3, 6): + from .ext_napoleon_pep526_data_google import PEP526GoogleClass + from .ext_napoleon_pep526_data_numpy import PEP526NumpyClass class NamedtupleSubclass(namedtuple('NamedtupleSubclass', ('attr1', 'attr2'))): @@ -53,19 +64,22 @@ class NamedtupleSubclassTest(BaseDocstringTest): Sample namedtuple subclass .. attribute:: attr1 - :type: Arbitrary type Quick description of attr1 + :type: Arbitrary type + .. attribute:: attr2 - :type: Another arbitrary type Quick description of attr2 + :type: Another arbitrary type + .. attribute:: attr3 - :type: Type Adds a newline after the type + + :type: Type """ self.assertEqual(expected, actual) @@ -289,6 +303,34 @@ class GoogleDocstringTest(BaseDocstringTest): """ Single line summary + Receive: + arg1 (list(int)): Description + arg2 (list[int]): Description + """, + """ + Single line summary + + :Receives: * **arg1** (*list(int)*) -- Description + * **arg2** (*list[int]*) -- Description + """ + ), ( + """ + Single line summary + + Receives: + arg1 (list(int)): Description + arg2 (list[int]): Description + """, + """ + Single line summary + + :Receives: * **arg1** (*list(int)*) -- Description + * **arg2** (*list[int]*) -- Description + """ + ), ( + """ + Single line summary + Yield: str:Extended description of yielded value @@ -409,9 +451,10 @@ Attributes: actual = str(GoogleDocstring(docstring)) expected = """\ .. attribute:: in_attr - :type: :class:`numpy.ndarray` super-dooper attribute + + :type: :class:`numpy.ndarray` """ self.assertEqual(expected, actual) @@ -423,9 +466,10 @@ Attributes: actual = str(GoogleDocstring(docstring)) expected = """\ .. attribute:: in_attr - :type: numpy.ndarray super-dooper attribute + + :type: numpy.ndarray """ self.assertEqual(expected, actual) @@ -1028,10 +1072,27 @@ You should listen to me! Sooper Warning: Stop hitting yourself! """, """:Warns: **Stop hitting yourself!** +"""), + ("""\ +Params Style: + arg1 (int): Description of arg1 + arg2 (str): Description of arg2 + +""", """\ +:Params Style: * **arg1** (*int*) -- Description of arg1 + * **arg2** (*str*) -- Description of arg2 +"""), + ("""\ +Returns Style: + description of custom section + +""", """:Returns Style: description of custom section """)) testConfig = Config(napoleon_custom_sections=['Really Important Details', - ('Sooper Warning', 'warns')]) + ('Sooper Warning', 'warns'), + ('Params Style', 'params_style'), + ('Returns Style', 'returns_style')]) for docstring, expected in docstrings: actual = str(GoogleDocstring(docstring, testConfig)) @@ -1059,12 +1120,77 @@ Methods: description -""" +""" # NOQA config = Config() actual = str(GoogleDocstring(docstring, config=config, app=None, what='module', options={'noindex': True})) self.assertEqual(expected, actual) + def test_keywords_with_types(self): + docstring = """\ +Do as you please + +Keyword Args: + gotham_is_yours (None): shall interfere. +""" + actual = str(GoogleDocstring(docstring)) + expected = """\ +Do as you please + +:keyword gotham_is_yours: shall interfere. +:kwtype gotham_is_yours: None +""" + self.assertEqual(expected, actual) + + def test_pep526_annotations(self): + if sys.version_info >= (3, 6): + # Test class attributes annotations + config = Config( + napoleon_attr_annotations=True + ) + actual = str(GoogleDocstring(cleandoc(PEP526GoogleClass.__doc__), config, app=None, what="class", + obj=PEP526GoogleClass)) + expected = """\ +Sample class with PEP 526 annotations and google docstring + +.. attribute:: attr1 + + Attr1 description. + + :type: int + +.. attribute:: attr2 + + Attr2 description. + + :type: str +""" + self.assertEqual(expected, actual) + + def test_preprocess_types(self): + docstring = """\ +Do as you please + +Yield: + str:Extended +""" + actual = str(GoogleDocstring(docstring)) + expected = """\ +Do as you please + +:Yields: *str* -- Extended +""" + self.assertEqual(expected, actual) + + config = Config(napoleon_preprocess_types=True) + actual = str(GoogleDocstring(docstring, config)) + expected = """\ +Do as you please + +:Yields: :class:`str` -- Extended +""" + self.assertEqual(expected, actual) + class NumpyDocstringTest(BaseDocstringTest): docstrings = [( @@ -1095,7 +1221,7 @@ class NumpyDocstringTest(BaseDocstringTest): """ Single line summary - :Parameters: **arg1** (*str*) -- Extended + :Parameters: **arg1** (:class:`str`) -- Extended description of arg1 """ ), ( @@ -1123,14 +1249,14 @@ class NumpyDocstringTest(BaseDocstringTest): """ Single line summary - :Parameters: * **arg1** (*str*) -- Extended + :Parameters: * **arg1** (:class:`str`) -- Extended description of arg1 - * **arg2** (*int*) -- Extended + * **arg2** (:class:`int`) -- Extended description of arg2 - :Keyword Arguments: * **kwarg1** (*str*) -- Extended + :Keyword Arguments: * **kwarg1** (:class:`str`) -- Extended description of kwarg1 - * **kwarg2** (*int*) -- Extended + * **kwarg2** (:class:`int`) -- Extended description of kwarg2 """ ), ( @@ -1146,7 +1272,7 @@ class NumpyDocstringTest(BaseDocstringTest): """ Single line summary - :returns: *str* -- Extended + :returns: :class:`str` -- Extended description of return value """ ), ( @@ -1162,7 +1288,7 @@ class NumpyDocstringTest(BaseDocstringTest): """ Single line summary - :returns: *str* -- Extended + :returns: :class:`str` -- Extended description of return value """ ), ( @@ -1181,7 +1307,7 @@ class NumpyDocstringTest(BaseDocstringTest): """ Single line summary - :Parameters: * **arg1** (*str*) -- Extended description of arg1 + :Parameters: * **arg1** (:class:`str`) -- Extended description of arg1 * **\\*args** -- Variable length argument list. * **\\*\\*kwargs** -- Arbitrary keyword arguments. """ @@ -1189,6 +1315,65 @@ class NumpyDocstringTest(BaseDocstringTest): """ Single line summary + Parameters + ---------- + arg1:str + Extended description of arg1 + *args, **kwargs: + Variable length argument list and arbitrary keyword arguments. + """, + """ + Single line summary + + :Parameters: * **arg1** (:class:`str`) -- Extended description of arg1 + * **\\*args, \\*\\*kwargs** -- Variable length argument list and arbitrary keyword arguments. + """ + ), ( + """ + Single line summary + + Receive + ------- + arg1:str + Extended + description of arg1 + arg2 : int + Extended + description of arg2 + """, + """ + Single line summary + + :Receives: * **arg1** (:class:`str`) -- Extended + description of arg1 + * **arg2** (:class:`int`) -- Extended + description of arg2 + """ + ), ( + """ + Single line summary + + Receives + -------- + arg1:str + Extended + description of arg1 + arg2 : int + Extended + description of arg2 + """, + """ + Single line summary + + :Receives: * **arg1** (:class:`str`) -- Extended + description of arg1 + * **arg2** (:class:`int`) -- Extended + description of arg2 + """ + ), ( + """ + Single line summary + Yield ----- str @@ -1198,7 +1383,7 @@ class NumpyDocstringTest(BaseDocstringTest): """ Single line summary - :Yields: *str* -- Extended + :Yields: :class:`str` -- Extended description of yielded value """ ), ( @@ -1214,7 +1399,7 @@ class NumpyDocstringTest(BaseDocstringTest): """ Single line summary - :Yields: *str* -- Extended + :Yields: :class:`str` -- Extended description of yielded value """ )] @@ -1263,12 +1448,34 @@ class NumpyDocstringTest(BaseDocstringTest): config = Config( napoleon_use_param=False, napoleon_use_rtype=False, - napoleon_use_keyword=False) + napoleon_use_keyword=False, + napoleon_preprocess_types=True) for docstring, expected in self.docstrings: actual = str(NumpyDocstring(dedent(docstring), config)) expected = dedent(expected) self.assertEqual(expected, actual) + def test_type_preprocessor(self): + docstring = dedent(""" + Single line summary + + Parameters + ---------- + arg1:str + Extended + description of arg1 + """) + + config = Config(napoleon_preprocess_types=False, napoleon_use_param=False) + actual = str(NumpyDocstring(docstring, config)) + expected = dedent(""" + Single line summary + + :Parameters: **arg1** (*str*) -- Extended + description of arg1 + """) + self.assertEqual(expected, actual) + def test_parameters_with_class_reference(self): docstring = """\ Parameters @@ -1292,6 +1499,32 @@ param1 : :class:`MyClass <name.space.MyClass>` instance """ self.assertEqual(expected, actual) + def test_multiple_parameters(self): + docstring = """\ +Parameters +---------- +x1, x2 : array_like + Input arrays, description of ``x1``, ``x2``. + +""" + + config = Config(napoleon_use_param=False) + actual = str(NumpyDocstring(docstring, config)) + expected = """\ +:Parameters: **x1, x2** (*array_like*) -- Input arrays, description of ``x1``, ``x2``. +""" + self.assertEqual(expected, actual) + + config = Config(napoleon_use_param=True) + actual = str(NumpyDocstring(dedent(docstring), config)) + expected = """\ +:param x1: Input arrays, description of ``x1``, ``x2``. +:type x1: array_like +:param x2: Input arrays, description of ``x1``, ``x2``. +:type x2: array_like +""" + self.assertEqual(expected, actual) + def test_parameters_without_class_reference(self): docstring = """\ Parameters @@ -1359,9 +1592,38 @@ numpy.multivariate_normal(mean, cov, shape=None, spam=None) .. seealso:: - :meth:`some`, :meth:`other`, :meth:`funcs` + :obj:`some`, :obj:`other`, :obj:`funcs` \n\ - :meth:`otherfunc` + :obj:`otherfunc` + relationship +""" + self.assertEqual(expected, actual) + + docstring = """\ +numpy.multivariate_normal(mean, cov, shape=None, spam=None) + +See Also +-------- +some, other, :func:`funcs` +otherfunc : relationship + +""" + translations = { + "other": "MyClass.other", + "otherfunc": ":func:`~my_package.otherfunc`", + } + config = Config(napoleon_type_aliases=translations) + app = mock.Mock() + actual = str(NumpyDocstring(docstring, config, app, "method")) + + expected = """\ +numpy.multivariate_normal(mean, cov, shape=None, spam=None) + +.. seealso:: + + :obj:`some`, :obj:`MyClass.other`, :func:`funcs` + \n\ + :func:`~my_package.otherfunc` relationship """ self.assertEqual(expected, actual) @@ -1430,6 +1692,52 @@ arg_ : type self.assertEqual(expected, actual) + def test_return_types(self): + docstring = dedent(""" + Returns + ------- + DataFrame + a dataframe + """) + expected = dedent(""" + :returns: a dataframe + :rtype: :class:`~pandas.DataFrame` + """) + translations = { + "DataFrame": "~pandas.DataFrame", + } + config = Config( + napoleon_use_param=True, + napoleon_use_rtype=True, + napoleon_preprocess_types=True, + napoleon_type_aliases=translations, + ) + actual = str(NumpyDocstring(docstring, config)) + self.assertEqual(expected, actual) + + def test_yield_types(self): + docstring = dedent(""" + Example Function + + Yields + ------ + scalar or array-like + The result of the computation + """) + expected = dedent(""" + Example Function + + :Yields: :term:`scalar` or :class:`array-like <numpy.ndarray>` -- The result of the computation + """) + translations = { + "scalar": ":term:`scalar`", + "array-like": ":class:`array-like <numpy.ndarray>`", + } + config = Config(napoleon_type_aliases=translations, napoleon_preprocess_types=True) + app = mock.Mock() + actual = str(NumpyDocstring(docstring, config, app, "method")) + self.assertEqual(expected, actual) + def test_raises_types(self): docstrings = [(""" Example Function @@ -1596,6 +1904,34 @@ Example Function Raises ------ +CustomError + If the dimensions couldn't be parsed. + +""", """ +Example Function + +:raises package.CustomError: If the dimensions couldn't be parsed. +"""), + ################################ + (""" +Example Function + +Raises +------ +AnotherError + If the dimensions couldn't be parsed. + +""", """ +Example Function + +:raises ~package.AnotherError: If the dimensions couldn't be parsed. +"""), + ################################ + (""" +Example Function + +Raises +------ :class:`exc.InvalidDimensionsError` :class:`exc.InvalidArgumentsError` @@ -1606,7 +1942,11 @@ Example Function :raises exc.InvalidArgumentsError: """)] for docstring, expected in docstrings: - config = Config() + translations = { + "CustomError": "package.CustomError", + "AnotherError": ":py:exc:`~package.AnotherError`", + } + config = Config(napoleon_type_aliases=translations, napoleon_preprocess_types=True) app = mock.Mock() actual = str(NumpyDocstring(docstring, config, app, "method")) self.assertEqual(expected, actual) @@ -1881,60 +2221,60 @@ definition_after_normal_text : int expected = """One line summary. -:Parameters: * **no_list** (*int*) - * **one_bullet_empty** (*int*) -- +:Parameters: * **no_list** (:class:`int`) + * **one_bullet_empty** (:class:`int`) -- * - * **one_bullet_single_line** (*int*) -- + * **one_bullet_single_line** (:class:`int`) -- - first line - * **one_bullet_two_lines** (*int*) -- + * **one_bullet_two_lines** (:class:`int`) -- + first line continued - * **two_bullets_single_line** (*int*) -- + * **two_bullets_single_line** (:class:`int`) -- - first line - second line - * **two_bullets_two_lines** (*int*) -- + * **two_bullets_two_lines** (:class:`int`) -- * first line continued * second line continued - * **one_enumeration_single_line** (*int*) -- + * **one_enumeration_single_line** (:class:`int`) -- 1. first line - * **one_enumeration_two_lines** (*int*) -- + * **one_enumeration_two_lines** (:class:`int`) -- 1) first line continued - * **two_enumerations_one_line** (*int*) -- + * **two_enumerations_one_line** (:class:`int`) -- (iii) first line (iv) second line - * **two_enumerations_two_lines** (*int*) -- + * **two_enumerations_two_lines** (:class:`int`) -- a. first line continued b. second line continued - * **one_definition_one_line** (*int*) -- + * **one_definition_one_line** (:class:`int`) -- item 1 first line - * **one_definition_two_lines** (*int*) -- + * **one_definition_two_lines** (:class:`int`) -- item 1 first line continued - * **two_definitions_one_line** (*int*) -- + * **two_definitions_one_line** (:class:`int`) -- item 1 first line item 2 second line - * **two_definitions_two_lines** (*int*) -- + * **two_definitions_two_lines** (:class:`int`) -- item 1 first line @@ -1942,14 +2282,14 @@ definition_after_normal_text : int item 2 second line continued - * **one_definition_blank_line** (*int*) -- + * **one_definition_blank_line** (:class:`int`) -- item 1 first line extra first line - * **two_definitions_blank_lines** (*int*) -- + * **two_definitions_blank_lines** (:class:`int`) -- item 1 @@ -1962,27 +2302,270 @@ definition_after_normal_text : int second line extra second line - * **definition_after_normal_text** (*int*) -- text line + * **definition_after_normal_text** (:class:`int`) -- text line item 1 first line """ - config = Config(napoleon_use_param=False) + config = Config(napoleon_use_param=False, napoleon_preprocess_types=True) actual = str(NumpyDocstring(docstring, config)) self.assertEqual(expected, actual) - def test_keywords_with_types(self): - docstring = """\ -Do as you please + def test_token_type(self): + tokens = ( + ("1", "literal"), + ("-4.6", "literal"), + ("2j", "literal"), + ("'string'", "literal"), + ('"another_string"', "literal"), + ("{1, 2}", "literal"), + ("{'va{ue', 'set'}", "literal"), + ("optional", "control"), + ("default", "control"), + (", ", "delimiter"), + (" of ", "delimiter"), + (" or ", "delimiter"), + (": ", "delimiter"), + ("True", "obj"), + ("None", "obj"), + ("name", "obj"), + (":py:class:`Enum`", "reference"), + ) -Keyword Args: - gotham_is_yours (None): shall interfere. -""" - actual = str(GoogleDocstring(docstring)) - expected = """\ -Do as you please + for token, expected in tokens: + actual = _token_type(token) + self.assertEqual(expected, actual) -:keyword gotham_is_yours: shall interfere. -:kwtype gotham_is_yours: None -""" + def test_tokenize_type_spec(self): + specs = ( + "str", + "defaultdict", + "int, float, or complex", + "int or float or None, optional", + '{"F", "C", "N"}', + "{'F', 'C', 'N'}, default: 'F'", + "{'F', 'C', 'N or C'}, default 'F'", + "str, default: 'F or C'", + "int, default: None", + "int, default None", + "int, default :obj:`None`", + '"ma{icious"', + r"'with \'quotes\''", + ) + + tokens = ( + ["str"], + ["defaultdict"], + ["int", ", ", "float", ", or ", "complex"], + ["int", " or ", "float", " or ", "None", ", ", "optional"], + ["{", '"F"', ", ", '"C"', ", ", '"N"', "}"], + ["{", "'F'", ", ", "'C'", ", ", "'N'", "}", ", ", "default", ": ", "'F'"], + ["{", "'F'", ", ", "'C'", ", ", "'N or C'", "}", ", ", "default", " ", "'F'"], + ["str", ", ", "default", ": ", "'F or C'"], + ["int", ", ", "default", ": ", "None"], + ["int", ", ", "default", " ", "None"], + ["int", ", ", "default", " ", ":obj:`None`"], + ['"ma{icious"'], + [r"'with \'quotes\''"], + ) + + for spec, expected in zip(specs, tokens): + actual = _tokenize_type_spec(spec) + self.assertEqual(expected, actual) + + def test_recombine_set_tokens(self): + tokens = ( + ["{", "1", ", ", "2", "}"], + ["{", '"F"', ", ", '"C"', ", ", '"N"', "}", ", ", "optional"], + ["{", "'F'", ", ", "'C'", ", ", "'N'", "}", ", ", "default", ": ", "None"], + ["{", "'F'", ", ", "'C'", ", ", "'N'", "}", ", ", "default", " ", "None"], + ) + + combined_tokens = ( + ["{1, 2}"], + ['{"F", "C", "N"}', ", ", "optional"], + ["{'F', 'C', 'N'}", ", ", "default", ": ", "None"], + ["{'F', 'C', 'N'}", ", ", "default", " ", "None"], + ) + + for tokens_, expected in zip(tokens, combined_tokens): + actual = _recombine_set_tokens(tokens_) + self.assertEqual(expected, actual) + + def test_recombine_set_tokens_invalid(self): + tokens = ( + ["{", "1", ", ", "2"], + ['"F"', ", ", '"C"', ", ", '"N"', "}", ", ", "optional"], + ["{", "1", ", ", "2", ", ", "default", ": ", "None"], + ) + combined_tokens = ( + ["{1, 2"], + ['"F"', ", ", '"C"', ", ", '"N"', "}", ", ", "optional"], + ["{1, 2", ", ", "default", ": ", "None"], + ) + + for tokens_, expected in zip(tokens, combined_tokens): + actual = _recombine_set_tokens(tokens_) + self.assertEqual(expected, actual) + + def test_convert_numpy_type_spec(self): + translations = { + "DataFrame": "pandas.DataFrame", + } + + specs = ( + "", + "optional", + "str, optional", + "int or float or None, default: None", + "int, default None", + '{"F", "C", "N"}', + "{'F', 'C', 'N'}, default: 'N'", + "{'F', 'C', 'N'}, default 'N'", + "DataFrame, optional", + ) + + converted = ( + "", + "*optional*", + ":class:`str`, *optional*", + ":class:`int` or :class:`float` or :obj:`None`, *default*: :obj:`None`", + ":class:`int`, *default* :obj:`None`", + '``{"F", "C", "N"}``', + "``{'F', 'C', 'N'}``, *default*: ``'N'``", + "``{'F', 'C', 'N'}``, *default* ``'N'``", + ":class:`pandas.DataFrame`, *optional*", + ) + + for spec, expected in zip(specs, converted): + actual = _convert_numpy_type_spec(spec, translations=translations) + self.assertEqual(expected, actual) + + def test_parameter_types(self): + docstring = dedent("""\ + Parameters + ---------- + param1 : DataFrame + the data to work on + param2 : int or float or None, optional + a parameter with different types + param3 : dict-like, optional + a optional mapping + param4 : int or float or None, optional + a optional parameter with different types + param5 : {"F", "C", "N"}, optional + a optional parameter with fixed values + param6 : int, default None + different default format + param7 : mapping of hashable to str, optional + a optional mapping + param8 : ... or Ellipsis + ellipsis + """) + expected = dedent("""\ + :param param1: the data to work on + :type param1: :class:`DataFrame` + :param param2: a parameter with different types + :type param2: :class:`int` or :class:`float` or :obj:`None`, *optional* + :param param3: a optional mapping + :type param3: :term:`dict-like <mapping>`, *optional* + :param param4: a optional parameter with different types + :type param4: :class:`int` or :class:`float` or :obj:`None`, *optional* + :param param5: a optional parameter with fixed values + :type param5: ``{"F", "C", "N"}``, *optional* + :param param6: different default format + :type param6: :class:`int`, *default* :obj:`None` + :param param7: a optional mapping + :type param7: :term:`mapping` of :term:`hashable` to :class:`str`, *optional* + :param param8: ellipsis + :type param8: :obj:`... <Ellipsis>` or :obj:`Ellipsis` + """) + translations = { + "dict-like": ":term:`dict-like <mapping>`", + "mapping": ":term:`mapping`", + "hashable": ":term:`hashable`", + } + config = Config( + napoleon_use_param=True, + napoleon_use_rtype=True, + napoleon_preprocess_types=True, + napoleon_type_aliases=translations, + ) + actual = str(NumpyDocstring(docstring, config)) self.assertEqual(expected, actual) + + +@contextmanager +def warns(warning, match): + match_re = re.compile(match) + try: + yield warning + finally: + raw_warnings = warning.getvalue() + warnings = [w for w in raw_warnings.split("\n") if w.strip()] + + assert len(warnings) == 1 and all(match_re.match(w) for w in warnings) + warning.truncate(0) + + +class TestNumpyDocstring: + def test_token_type_invalid(self, warning): + tokens = ( + "{1, 2", + "}", + "'abc", + "def'", + '"ghi', + 'jkl"', + ) + errors = ( + r".+: invalid value set \(missing closing brace\):", + r".+: invalid value set \(missing opening brace\):", + r".+: malformed string literal \(missing closing quote\):", + r".+: malformed string literal \(missing opening quote\):", + r".+: malformed string literal \(missing closing quote\):", + r".+: malformed string literal \(missing opening quote\):", + ) + for token, error in zip(tokens, errors): + with warns(warning, match=error): + _token_type(token) + + @pytest.mark.parametrize( + ("name", "expected"), + ( + ("x, y, z", "x, y, z"), + ("*args, **kwargs", r"\*args, \*\*kwargs"), + ("*x, **y", r"\*x, \*\*y"), + ), + ) + def test_escape_args_and_kwargs(self, name, expected): + numpy_docstring = NumpyDocstring("") + actual = numpy_docstring._escape_args_and_kwargs(name) + + assert actual == expected + + def test_pep526_annotations(self): + if sys.version_info >= (3, 6): + # test class attributes annotations + config = Config( + napoleon_attr_annotations=True + ) + actual = str(NumpyDocstring(cleandoc(PEP526NumpyClass.__doc__), config, app=None, what="class", + obj=PEP526NumpyClass)) + expected = """\ +Sample class with PEP 526 annotations and numpy docstring + +.. attribute:: attr1 + + Attr1 description + + :type: int + +.. attribute:: attr2 + + Attr2 description + + :type: str +""" + print(actual) + assert expected == actual diff --git a/tests/test_ext_napoleon_iterators.py b/tests/test_ext_napoleon_iterators.py index de28031cb..45b558794 100644 --- a/tests/test_ext_napoleon_iterators.py +++ b/tests/test_ext_napoleon_iterators.py @@ -5,13 +5,13 @@ Tests for :mod:`sphinx.ext.napoleon.iterators` module. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from unittest import TestCase -from sphinx.ext.napoleon.iterators import peek_iter, modify_iter +from sphinx.ext.napoleon.iterators import modify_iter, peek_iter class BaseIteratorsTest(TestCase): diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index 7b4fdeabe..b6fb2549c 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -4,7 +4,7 @@ Test sphinx.ext.todo extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_viewcode.py b/tests/test_ext_viewcode.py index 3d9ea27d7..d75fb7196 100644 --- a/tests/test_ext_viewcode.py +++ b/tests/test_ext_viewcode.py @@ -4,7 +4,7 @@ Test sphinx.ext.viewcode extension. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -49,6 +49,27 @@ def test_viewcode(app, status, warning): '<span> """</span></div>\n') in result +@pytest.mark.sphinx('epub', testroot='ext-viewcode') +def test_viewcode_epub_default(app, status, warning): + app.builder.build_all() + + assert not (app.outdir / '_modules/spam/mod1.xhtml').exists() + + result = (app.outdir / 'index.xhtml').read_text() + assert result.count('href="_modules/spam/mod1.xhtml#func1"') == 0 + + +@pytest.mark.sphinx('epub', testroot='ext-viewcode', + confoverrides={'viewcode_enable_epub': True}) +def test_viewcode_epub_enabled(app, status, warning): + app.builder.build_all() + + assert (app.outdir / '_modules/spam/mod1.xhtml').exists() + + result = (app.outdir / 'index.xhtml').read_text() + assert result.count('href="_modules/spam/mod1.xhtml#func1"') == 2 + + @pytest.mark.sphinx(testroot='ext-viewcode', tags=['test_linkcode']) def test_linkcode(app, status, warning): app.builder.build(['objects']) diff --git a/tests/test_highlighting.py b/tests/test_highlighting.py index c2b470a6b..a51e25688 100644 --- a/tests/test_highlighting.py +++ b/tests/test_highlighting.py @@ -4,7 +4,7 @@ Test the Pygments highlighting bridge. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,7 +12,7 @@ from unittest import mock from pygments.formatters.html import HtmlFormatter from pygments.lexer import RegexLexer -from pygments.token import Text, Name +from pygments.token import Name, Text from sphinx.highlighting import PygmentsBridge diff --git a/tests/test_intl.py b/tests/test_intl.py index d0c64b589..00f599595 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -5,7 +5,7 @@ Test message patching for internationalization purposes. Runs the text builder in the test root. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,14 +13,13 @@ import os import re import pytest -from babel.messages import pofile, mofile +from babel.messages import mofile, pofile +from babel.messages.catalog import Catalog from docutils import nodes -from sphinx.testing.util import ( - path, etree_parse, strip_escseq, - assert_re_search, assert_not_re_search, assert_startswith, assert_node -) - +from sphinx import locale +from sphinx.testing.util import (assert_node, assert_not_re_search, assert_re_search, + assert_startswith, etree_parse, path, strip_escseq) sphinx_intl = pytest.mark.sphinx( testroot='intl', @@ -93,15 +92,6 @@ def assert_count(expected_expr, result, count): @sphinx_intl @pytest.mark.sphinx('text') @pytest.mark.test_params(shared_result='test_intl_basic') -def test_text_toctree(app): - app.build() - result = (app.outdir / 'index.txt').read_text() - assert_startswith(result, "CONTENTS\n********\n\nTABLE OF CONTENTS\n") - - -@sphinx_intl -@pytest.mark.sphinx('text') -@pytest.mark.test_params(shared_result='test_intl_basic') def test_text_emit_warnings(app, warning): app.build() # test warnings in translation @@ -437,11 +427,16 @@ def test_text_admonitions(app): @pytest.mark.test_params(shared_result='test_intl_gettext') def test_gettext_toctree(app): app.build() - # --- toctree + # --- toctree (index.rst) expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'index.po') actual = read_po(app.outdir / 'index.pot') for expect_msg in [m for m in expect if m.id]: assert expect_msg.id in [m.id for m in actual if m.id] + # --- toctree (toctree.rst) + expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'toctree.po') + actual = read_po(app.outdir / 'toctree.pot') + for expect_msg in [m for m in expect if m.id]: + assert expect_msg.id in [m.id for m in actual if m.id] @sphinx_intl @@ -469,23 +464,16 @@ def test_text_table(app): @sphinx_intl -@pytest.mark.sphinx('gettext') -@pytest.mark.test_params(shared_result='test_intl_gettext') -def test_gettext_toctree(app): - app.build() - # --- toctree - expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'toctree.po') - actual = read_po(app.outdir / 'toctree.pot') - for expect_msg in [m for m in expect if m.id]: - assert expect_msg.id in [m.id for m in actual if m.id] - - -@sphinx_intl @pytest.mark.sphinx('text') @pytest.mark.test_params(shared_result='test_intl_basic') def test_text_toctree(app): app.build() - # --- toctree + # --- toctree (index.rst) + # Note: index.rst contains contents that is not shown in text. + result = (app.outdir / 'index.txt').read_text() + assert 'CONTENTS' in result + assert 'TABLE OF CONTENTS' in result + # --- toctree (toctree.rst) result = (app.outdir / 'toctree.txt').read_text() expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'toctree.po') for expect_msg in [m for m in expect if m.id]: @@ -956,9 +944,9 @@ def test_xml_role_xref(app): 'glossary_terms#term-Some-term']) assert_elem( para2[1], - ['LINK TO', 'SAME TYPE LINKS', 'AND', - "I18N ROCK'N ROLE XREF", '.'], - ['same-type-links', 'i18n-role-xref']) + ['LINK TO', 'LABEL', 'AND', + 'SAME TYPE LINKS', 'AND', 'SAME TYPE LINKS', '.'], + ['i18n-role-xref', 'same-type-links', 'same-type-links']) assert_elem( para2[2], ['LINK TO', 'I18N WITH GLOSSARY TERMS', 'AND', 'CONTENTS', '.'], @@ -1289,3 +1277,30 @@ def test_image_glob_intl_using_figure_language_filename(app): def getwarning(warnings): return strip_escseq(warnings.getvalue().replace(os.sep, '/')) + + +@pytest.mark.sphinx('html', testroot='basic', confoverrides={'language': 'de'}) +def test_customize_system_message(make_app, app_params, sphinx_test_tempdir): + try: + # clear translators cache + locale.translators.clear() + + # prepare message catalog (.po) + locale_dir = sphinx_test_tempdir / 'basic' / 'locales' / 'de' / 'LC_MESSAGES' + locale_dir.makedirs() + with (locale_dir / 'sphinx.po').open('wb') as f: + catalog = Catalog() + catalog.add('Quick search', 'QUICK SEARCH') + pofile.write_po(f, catalog) + + # construct application and convert po file to .mo + args, kwargs = app_params + app = make_app(*args, **kwargs) + assert (locale_dir / 'sphinx.mo').exists() + assert app.translator.gettext('Quick search') == 'QUICK SEARCH' + + app.build() + content = (app.outdir / 'index.html').read_text() + assert 'QUICK SEARCH' in content + finally: + locale.translators.clear() diff --git a/tests/test_locale.py b/tests/test_locale.py index a744a5ff7..5d3dbf17f 100644 --- a/tests/test_locale.py +++ b/tests/test_locale.py @@ -4,7 +4,7 @@ Test locale. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_markup.py b/tests/test_markup.py index 5fb835605..8341b8826 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -4,28 +4,26 @@ Test various Sphinx-specific markup extensions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re import pytest -from docutils import frontend, utils, nodes +from docutils import frontend, nodes, utils from docutils.parsers.rst import Parser as RstParser from sphinx import addnodes from sphinx.builders.html.transforms import KeyboardTransform from sphinx.builders.latex import LaTeXBuilder -from sphinx.builders.latex.theming import ThemeFactory from sphinx.roles import XRefRole from sphinx.testing.util import Struct, assert_node from sphinx.transforms import SphinxSmartQuotes -from sphinx.util import docutils -from sphinx.util import texescape +from sphinx.util import docutils, texescape from sphinx.util.docutils import sphinx_domains -from sphinx.writers.html import HTMLWriter, HTMLTranslator -from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator +from sphinx.writers.html import HTMLTranslator, HTMLWriter +from sphinx.writers.latex import LaTeXTranslator, LaTeXWriter @pytest.fixture @@ -246,7 +244,7 @@ def get_verifier(verify, verify_re): # kbd role 'verify', ':kbd:`Control+X`', - ('<p><kbd class="kbd docutils literal notranslate">' + ('<p><kbd class="kbd compound docutils literal notranslate">' '<kbd class="kbd docutils literal notranslate">Control</kbd>' '+' '<kbd class="kbd docutils literal notranslate">X</kbd>' @@ -256,8 +254,19 @@ def get_verifier(verify, verify_re): ( # kbd role 'verify', + ':kbd:`Alt+^`', + ('<p><kbd class="kbd compound docutils literal notranslate">' + '<kbd class="kbd docutils literal notranslate">Alt</kbd>' + '+' + '<kbd class="kbd docutils literal notranslate">^</kbd>' + '</kbd></p>'), + '\\sphinxkeyboard{\\sphinxupquote{Alt+\\textasciicircum{}}}', + ), + ( + # kbd role + 'verify', ':kbd:`M-x M-s`', - ('<p><kbd class="kbd docutils literal notranslate">' + ('<p><kbd class="kbd compound docutils literal notranslate">' '<kbd class="kbd docutils literal notranslate">M</kbd>' '-' '<kbd class="kbd docutils literal notranslate">x</kbd>' @@ -269,6 +278,20 @@ def get_verifier(verify, verify_re): '\\sphinxkeyboard{\\sphinxupquote{M\\sphinxhyphen{}x M\\sphinxhyphen{}s}}', ), ( + # kbd role + 'verify', + ':kbd:`-`', + '<p><kbd class="kbd docutils literal notranslate">-</kbd></p>', + '\\sphinxkeyboard{\\sphinxupquote{\\sphinxhyphen{}}}', + ), + ( + # kbd role + 'verify', + ':kbd:`Caps Lock`', + '<p><kbd class="kbd docutils literal notranslate">Caps Lock</kbd></p>', + '\\sphinxkeyboard{\\sphinxupquote{Caps Lock}}', + ), + ( # non-interpolation of dashes in option role 'verify_re', ':option:`--with-option`', diff --git a/tests/test_metadata.py b/tests/test_metadata.py index e345488e6..465386430 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -4,7 +4,7 @@ Test our handling of metadata in files with bibliographic metadata. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_parser.py b/tests/test_parser.py index 4b0cf17a3..df22750e3 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -4,7 +4,7 @@ Tests parsers module. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -50,7 +50,7 @@ def test_RSTParser_prolog_epilog(RSTStateMachine, app): (content, _), _ = RSTStateMachine().run.call_args assert list(content.xitems()) == [('dummy.rst', 0, 'hello Sphinx world'), ('dummy.rst', 1, 'Sphinx is a document generator'), - ('<generated>', 0, ''), + ('dummy.rst', 2, ''), ('<rst_epilog>', 0, 'this is rst_epilog'), ('<rst_epilog>', 1, 'good-bye reST!')] diff --git a/tests/test_project.py b/tests/test_project.py index 50b06f7b8..03fa1d49f 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -4,7 +4,7 @@ Tests project module. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,7 +13,6 @@ from collections import OrderedDict import pytest from sphinx.project import Project -from sphinx.testing.comparer import PathComparer def test_project_discover(rootdir): diff --git a/tests/test_pycode.py b/tests/test_pycode.py index 458e813f6..bbcc42a52 100644 --- a/tests/test_pycode.py +++ b/tests/test_pycode.py @@ -4,20 +4,22 @@ Test pycode. - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import sys + import pytest import sphinx -from sphinx.pycode import ModuleAnalyzer from sphinx.errors import PycodeError +from sphinx.pycode import ModuleAnalyzer SPHINX_MODULE_PATH = os.path.splitext(sphinx.__file__)[0] + '.py' + def test_ModuleAnalyzer_get_module_source(): assert ModuleAnalyzer.get_module_source('sphinx') == (sphinx.__file__, sphinx.__loader__.get_source('sphinx')) @@ -26,7 +28,7 @@ def test_ModuleAnalyzer_get_module_source(): ModuleAnalyzer.get_module_source('builtins') with pytest.raises(PycodeError): ModuleAnalyzer.get_module_source('itertools') - + def test_ModuleAnalyzer_for_string(): analyzer = ModuleAnalyzer.for_string('print("Hello world")', 'module_name') diff --git a/tests/test_pycode_ast.py b/tests/test_pycode_ast.py index 9b12d24d5..e80062351 100644 --- a/tests/test_pycode_ast.py +++ b/tests/test_pycode_ast.py @@ -4,7 +4,7 @@ Test pycode.ast - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -53,12 +53,12 @@ from sphinx.pycode import ast ("+ a", "+ a"), # UAdd ("- 1", "- 1"), # UnaryOp ("- a", "- a"), # USub - ("(1, 2, 3)", "1, 2, 3"), # Tuple + ("(1, 2, 3)", "(1, 2, 3)"), # Tuple ("()", "()"), # Tuple (empty) ]) def test_unparse(source, expected): module = ast.parse(source) - assert ast.unparse(module.body[0].value) == expected + assert ast.unparse(module.body[0].value, source) == expected def test_unparse_None(): @@ -66,8 +66,12 @@ def test_unparse_None(): @pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.') -def test_unparse_py38(): - source = "lambda x=0, /, y=1, *args, z, **kwargs: x + y + z" - expected = "lambda x=0, /, y=1, *args, z, **kwargs: ..." +@pytest.mark.parametrize('source,expected', [ + ("lambda x=0, /, y=1, *args, z, **kwargs: x + y + z", + "lambda x=0, /, y=1, *args, z, **kwargs: ..."), # posonlyargs + ("0x1234", "0x1234"), # Constant + ("1_000_000", "1_000_000"), # Constant +]) +def test_unparse_py38(source, expected): module = ast.parse(source) - assert ast.unparse(module.body[0].value) == expected + assert ast.unparse(module.body[0].value, source) == expected diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py index 398c9f8a4..9169315fc 100644 --- a/tests/test_pycode_parser.py +++ b/tests/test_pycode_parser.py @@ -4,7 +4,7 @@ Test pycode.parser. - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -13,6 +13,7 @@ import sys import pytest from sphinx.pycode.parser import Parser +from sphinx.util.inspect import signature_from_str def test_comment_picker_basic(): @@ -452,3 +453,80 @@ def test_typing_final_not_imported(): parser = Parser(source) parser.parse() assert parser.finals == [] + + +def test_typing_overload(): + source = ('import typing\n' + '\n' + '@typing.overload\n' + 'def func(x: int, y: int) -> int: pass\n' + '\n' + '@typing.overload\n' + 'def func(x: str, y: str) -> str: pass\n' + '\n' + 'def func(x, y): pass\n') + parser = Parser(source) + parser.parse() + assert parser.overloads == {'func': [signature_from_str('(x: int, y: int) -> int'), + signature_from_str('(x: str, y: str) -> str')]} + + +def test_typing_overload_from_import(): + source = ('from typing import overload\n' + '\n' + '@overload\n' + 'def func(x: int, y: int) -> int: pass\n' + '\n' + '@overload\n' + 'def func(x: str, y: str) -> str: pass\n' + '\n' + 'def func(x, y): pass\n') + parser = Parser(source) + parser.parse() + assert parser.overloads == {'func': [signature_from_str('(x: int, y: int) -> int'), + signature_from_str('(x: str, y: str) -> str')]} + + +def test_typing_overload_import_as(): + source = ('import typing as foo\n' + '\n' + '@foo.overload\n' + 'def func(x: int, y: int) -> int: pass\n' + '\n' + '@foo.overload\n' + 'def func(x: str, y: str) -> str: pass\n' + '\n' + 'def func(x, y): pass\n') + parser = Parser(source) + parser.parse() + assert parser.overloads == {'func': [signature_from_str('(x: int, y: int) -> int'), + signature_from_str('(x: str, y: str) -> str')]} + + +def test_typing_overload_from_import_as(): + source = ('from typing import overload as bar\n' + '\n' + '@bar\n' + 'def func(x: int, y: int) -> int: pass\n' + '\n' + '@bar\n' + 'def func(x: str, y: str) -> str: pass\n' + '\n' + 'def func(x, y): pass\n') + parser = Parser(source) + parser.parse() + assert parser.overloads == {'func': [signature_from_str('(x: int, y: int) -> int'), + signature_from_str('(x: str, y: str) -> str')]} + + +def test_typing_overload_not_imported(): + source = ('@typing.final\n' + 'def func(x: int, y: int) -> int: pass\n' + '\n' + '@typing.final\n' + 'def func(x: str, y: str) -> str: pass\n' + '\n' + 'def func(x, y): pass\n') + parser = Parser(source) + parser.parse() + assert parser.overloads == {} diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index bdd7073d1..11086f5f6 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -4,7 +4,7 @@ Test the sphinx.quickstart module. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -15,10 +15,9 @@ import pytest from sphinx import application from sphinx.cmd import quickstart as qs -from sphinx.util.console import nocolor, coloron +from sphinx.util.console import coloron, nocolor from sphinx.util.pycompat import execfile_ - warnfile = StringIO() diff --git a/tests/test_roles.py b/tests/test_roles.py index d1ed7f439..553a50853 100644 --- a/tests/test_roles.py +++ b/tests/test_roles.py @@ -4,7 +4,7 @@ Test sphinx.roles - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_search.py b/tests/test_search.py index a4cefbc67..1ceb6d55b 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -4,12 +4,12 @@ Test the search index builder. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from io import BytesIO from collections import namedtuple +from io import BytesIO import pytest from docutils import frontend, utils diff --git a/tests/test_setup_command.py b/tests/test_setup_command.py index 14a687ada..52dad14fd 100644 --- a/tests/test_setup_command.py +++ b/tests/test_setup_command.py @@ -4,7 +4,7 @@ Test setup_command for distutils. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_smartquotes.py b/tests/test_smartquotes.py index 6276e6a74..0cc0681dc 100644 --- a/tests/test_smartquotes.py +++ b/tests/test_smartquotes.py @@ -4,7 +4,7 @@ Test smart quotes. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_templating.py b/tests/test_templating.py index f2c1d563b..3a7c58216 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -4,7 +4,7 @@ Test templating. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_theming.py b/tests/test_theming.py index 93671eab8..0dded0725 100644 --- a/tests/test_theming.py +++ b/tests/test_theming.py @@ -4,15 +4,15 @@ Test the Theme class. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os import alabaster - import pytest + from sphinx.theming import ThemeError @@ -81,7 +81,7 @@ def test_js_source(app, status, warning): jquery_src = (app.outdir / '_static' / 'jquery-{v}.js'.format(v=v)).read_text() assert 'jQuery JavaScript Library v{v}'.format(v=v) in jquery_src, msg - v = '1.3.1' + v = '1.12.0' msg = 'underscore.js version does not match to {v}'.format(v=v) underscore_min = (app.outdir / '_static' / 'underscore.js').read_text() assert 'Underscore.js {v}'.format(v=v) in underscore_min, msg diff --git a/tests/test_toctree.py b/tests/test_toctree.py index 38886769a..7a9f7a578 100644 --- a/tests/test_toctree.py +++ b/tests/test_toctree.py @@ -4,7 +4,7 @@ Test the HTML builder and check output against XPath. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re diff --git a/tests/test_transforms_post_transforms_code.py b/tests/test_transforms_post_transforms_code.py index 880f4711b..449cba78a 100644 --- a/tests/test_transforms_post_transforms_code.py +++ b/tests/test_transforms_post_transforms_code.py @@ -2,7 +2,7 @@ test_transforms_post_transforms_code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -19,6 +19,23 @@ def test_trim_doctest_flags_html(app, status, warning): assert 'BAZ' not in result assert 'QUX' not in result assert 'QUUX' not in result + assert 'CORGE' not in result + assert 'GRAULT' in result + + +@pytest.mark.sphinx('html', testroot='trim_doctest_flags', + confoverrides={'trim_doctest_flags': False}) +def test_trim_doctest_flags_disabled(app, status, warning): + app.build() + + result = (app.outdir / 'index.html').read_text() + assert 'FOO' in result + assert 'BAR' in result + assert 'BAZ' in result + assert 'QUX' in result + assert 'QUUX' not in result + assert 'CORGE' not in result + assert 'GRAULT' in result @pytest.mark.sphinx('latex', testroot='trim_doctest_flags') @@ -31,3 +48,5 @@ def test_trim_doctest_flags_latex(app, status, warning): assert 'BAZ' not in result assert 'QUX' not in result assert 'QUUX' not in result + assert 'CORGE' not in result + assert 'GRAULT' in result diff --git a/tests/test_util.py b/tests/test_util.py index 434d96d3a..9b25aac58 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -4,7 +4,7 @@ Tests util functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,14 +14,11 @@ from unittest.mock import patch import pytest -import sphinx -from sphinx.errors import ExtensionError, PycodeError +from sphinx.errors import ExtensionError from sphinx.testing.util import strip_escseq -from sphinx.util import ( - SkipProgressMessage, display_chunk, encode_uri, ensuredir, - import_object, parselinenos, progress_message, status_iterator, xmlname_checker -) -from sphinx.util import logging +from sphinx.util import (SkipProgressMessage, display_chunk, encode_uri, ensuredir, + import_object, logging, parselinenos, progress_message, + status_iterator, xmlname_checker) def test_encode_uri(): diff --git a/tests/test_util_docstrings.py b/tests/test_util_docstrings.py index a57e3f9b1..543feca2a 100644 --- a/tests/test_util_docstrings.py +++ b/tests/test_util_docstrings.py @@ -4,13 +4,11 @@ Test sphinx.util.docstrings. - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from sphinx.util.docstrings import ( - extract_metadata, prepare_docstring, prepare_commentdoc -) +from sphinx.util.docstrings import extract_metadata, prepare_commentdoc, prepare_docstring def test_extract_metadata(): diff --git a/tests/test_util_docutils.py b/tests/test_util_docutils.py index a22cf277a..9c4e373cf 100644 --- a/tests/test_util_docutils.py +++ b/tests/test_util_docutils.py @@ -4,7 +4,7 @@ Tests util.utils functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -12,9 +12,8 @@ import os from docutils import nodes -from sphinx.util.docutils import ( - SphinxFileOutput, SphinxTranslator, docutils_namespace, new_document, register_node -) +from sphinx.util.docutils import (SphinxFileOutput, SphinxTranslator, docutils_namespace, + new_document, register_node) def test_register_node(): diff --git a/tests/test_util_fileutil.py b/tests/test_util_fileutil.py index e9c80d5b6..fd2f186c2 100644 --- a/tests/test_util_fileutil.py +++ b/tests/test_util_fileutil.py @@ -4,7 +4,7 @@ Tests sphinx.util.fileutil functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_util_i18n.py b/tests/test_util_i18n.py index e6e828efa..180350e86 100644 --- a/tests/test_util_i18n.py +++ b/tests/test_util_i18n.py @@ -4,7 +4,7 @@ Test i18n util. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -87,9 +87,17 @@ def test_format_date(): assert i18n.format_date(format, date=datet) == 'Feb 7, 2016, 5:11:17 AM' assert i18n.format_date(format, date=date) == 'Feb 7, 2016' + # timezone + format = '%Z' + assert i18n.format_date(format, date=datet) == 'UTC' + format = '%z' + assert i18n.format_date(format, date=datet) == '+0000' + @pytest.mark.xfail(os.name != 'posix', reason="Path separators don't match on windows") def test_get_filename_for_language(app): + app.env.temp_data['docname'] = 'index' + # language is None app.env.config.language = None assert app.env.config.language is None @@ -145,6 +153,17 @@ def test_get_filename_for_language(app): with pytest.raises(SphinxError): i18n.get_image_filename_for_language('foo.png', app.env) + # docpath (for a document in the top of source directory) + app.env.config.language = 'en' + app.env.config.figure_language_filename = '/{docpath}{language}/{basename}{ext}' + assert (i18n.get_image_filename_for_language('foo.png', app.env) == + '/en/foo.png') + + # docpath (for a document in the sub directory) + app.env.temp_data['docname'] = 'subdir/index' + assert (i18n.get_image_filename_for_language('foo.png', app.env) == + '/subdir/en/foo.png') + def test_CatalogRepository(tempdir): (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs() diff --git a/tests/test_util_images.py b/tests/test_util_images.py index 2a256577f..bf71f4c49 100644 --- a/tests/test_util_images.py +++ b/tests/test_util_images.py @@ -4,15 +4,14 @@ Test images util. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest -from sphinx.util.images import ( - get_image_size, guess_mimetype, get_image_extension, parse_data_uri -) +from sphinx.util.images import (get_image_extension, get_image_size, guess_mimetype, + parse_data_uri) GIF_FILENAME = 'img.gif' PNG_FILENAME = 'img.png' diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index fa0ff84e1..863f44921 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -4,21 +4,22 @@ Tests util.inspect functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -import _testcapi +import ast import datetime import functools import sys import types from inspect import Parameter +import _testcapi import pytest from sphinx.util import inspect -from sphinx.util.inspect import stringify_signature, is_builtin_class_method +from sphinx.util.inspect import stringify_signature def test_signature(): @@ -99,7 +100,7 @@ def test_signature_methods(): # wrapped bound method sig = inspect.signature(wrapped_bound_method) - assert stringify_signature(sig) == '(*args, **kwargs)' + assert stringify_signature(sig) == '(arg1, **kwargs)' def test_signature_partialmethod(): @@ -128,8 +129,8 @@ def test_signature_partialmethod(): def test_signature_annotations(): - from typing_test_data import (f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, - f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, Node) + from .typing_test_data import (Node, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, + f13, f14, f15, f16, f17, f18, f19, f20, f21) # Class annotations sig = inspect.signature(f0) @@ -161,7 +162,7 @@ def test_signature_annotations(): # Space around '=' for defaults sig = inspect.signature(f7) - assert stringify_signature(sig) == '(x: int = None, y: dict = {}) -> None' + assert stringify_signature(sig) == '(x: Optional[int] = None, y: dict = {}) -> None' # Callable types sig = inspect.signature(f8) @@ -176,7 +177,10 @@ def test_signature_annotations(): # Instance annotations sig = inspect.signature(f11) - assert stringify_signature(sig) == '(x: CustomAnnotation, y: 123) -> None' + if sys.version_info < (3, 10): + assert stringify_signature(sig) == '(x: CustomAnnotation, y: 123) -> None' + else: + assert stringify_signature(sig) == '(x: CustomAnnotation(), y: 123) -> None' # tuple with more than two items sig = inspect.signature(f12) @@ -213,15 +217,19 @@ def test_signature_annotations(): sig = inspect.signature(f19) assert stringify_signature(sig) == '(*args: int, **kwargs: str)' + # default value is inspect.Signature.empty + sig = inspect.signature(f21) + assert stringify_signature(sig) == "(arg1='whatever', arg2)" + # type hints by string sig = inspect.signature(Node.children) if (3, 5, 0) <= sys.version_info < (3, 5, 3): assert stringify_signature(sig) == '(self) -> List[Node]' else: - assert stringify_signature(sig) == '(self) -> List[typing_test_data.Node]' + assert stringify_signature(sig) == '(self) -> List[tests.typing_test_data.Node]' sig = inspect.signature(Node.__init__) - assert stringify_signature(sig) == '(self, parent: Optional[Node]) -> None' + assert stringify_signature(sig) == '(self, parent: Optional[tests.typing_test_data.Node]) -> None' # show_annotation is False sig = inspect.signature(f7) @@ -229,13 +237,13 @@ def test_signature_annotations(): # show_return_annotation is False sig = inspect.signature(f7) - assert stringify_signature(sig, show_return_annotation=False) == '(x: int = None, y: dict = {})' + assert stringify_signature(sig, show_return_annotation=False) == '(x: Optional[int] = None, y: dict = {})' @pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.') @pytest.mark.sphinx(testroot='ext-autodoc') def test_signature_annotations_py38(app): - from target.pep570 import foo, bar, baz, qux + from target.pep570 import bar, baz, foo, qux # case: separator at head sig = inspect.signature(foo) @@ -350,6 +358,38 @@ def test_signature_from_str_invalid(): inspect.signature_from_str('') +def test_signature_from_ast(): + signature = 'def func(a, b, *args, c=0, d="blah", **kwargs): pass' + tree = ast.parse(signature) + sig = inspect.signature_from_ast(tree.body[0]) + assert list(sig.parameters.keys()) == ['a', 'b', 'args', 'c', 'd', 'kwargs'] + assert sig.parameters['a'].name == 'a' + assert sig.parameters['a'].kind == Parameter.POSITIONAL_OR_KEYWORD + assert sig.parameters['a'].default == Parameter.empty + assert sig.parameters['a'].annotation == Parameter.empty + assert sig.parameters['b'].name == 'b' + assert sig.parameters['b'].kind == Parameter.POSITIONAL_OR_KEYWORD + assert sig.parameters['b'].default == Parameter.empty + assert sig.parameters['b'].annotation == Parameter.empty + assert sig.parameters['args'].name == 'args' + assert sig.parameters['args'].kind == Parameter.VAR_POSITIONAL + assert sig.parameters['args'].default == Parameter.empty + assert sig.parameters['args'].annotation == Parameter.empty + assert sig.parameters['c'].name == 'c' + assert sig.parameters['c'].kind == Parameter.KEYWORD_ONLY + assert sig.parameters['c'].default == '0' + assert sig.parameters['c'].annotation == Parameter.empty + assert sig.parameters['d'].name == 'd' + assert sig.parameters['d'].kind == Parameter.KEYWORD_ONLY + assert sig.parameters['d'].default == "'blah'" + assert sig.parameters['d'].annotation == Parameter.empty + assert sig.parameters['kwargs'].name == 'kwargs' + assert sig.parameters['kwargs'].kind == Parameter.VAR_KEYWORD + assert sig.parameters['kwargs'].default == Parameter.empty + assert sig.parameters['kwargs'].annotation == Parameter.empty + assert sig.return_annotation == Parameter.empty + + def test_safe_getattr_with_default(): class Foo: def __getattr__(self, item): @@ -453,6 +493,28 @@ def test_dict_customtype(): assert "<CustomType(2)>: 2" in description +def test_getslots(): + class Foo: + pass + + class Bar: + __slots__ = ['attr'] + + class Baz: + __slots__ = {'attr': 'docstring'} + + class Qux: + __slots__ = 'attr' + + assert inspect.getslots(Foo) is None + assert inspect.getslots(Bar) == {'attr': None} + assert inspect.getslots(Baz) == {'attr': 'docstring'} + assert inspect.getslots(Qux) == {'attr': None} + + with pytest.raises(TypeError): + inspect.getslots(Bar()) + + @pytest.mark.sphinx(testroot='ext-autodoc') def test_isclassmethod(app): from target.methods import Base, Inherited @@ -491,8 +553,7 @@ def test_iscoroutinefunction(app): @pytest.mark.sphinx(testroot='ext-autodoc') def test_isfunction(app): - from target.functions import builtin_func, partial_builtin_func - from target.functions import func, partial_func + from target.functions import builtin_func, func, partial_builtin_func, partial_func from target.methods import Base assert inspect.isfunction(func) is True # function @@ -506,8 +567,7 @@ def test_isfunction(app): @pytest.mark.sphinx(testroot='ext-autodoc') def test_isbuiltin(app): - from target.functions import builtin_func, partial_builtin_func - from target.functions import func, partial_func + from target.functions import builtin_func, func, partial_builtin_func, partial_func from target.methods import Base assert inspect.isbuiltin(builtin_func) is True # builtin function diff --git a/tests/test_util_inventory.py b/tests/test_util_inventory.py index 2183313e1..f12ae5011 100644 --- a/tests/test_util_inventory.py +++ b/tests/test_util_inventory.py @@ -4,7 +4,7 @@ Test inventory util functions. - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -14,20 +14,20 @@ from io import BytesIO from sphinx.ext.intersphinx import InventoryFile -inventory_v1 = '''\ +inventory_v1 = b'''\ # Sphinx inventory version 1 # Project: foo # Version: 1.0 module mod foo.html module.cls class foo.html -'''.encode() +''' -inventory_v2 = '''\ +inventory_v2 = b'''\ # Sphinx inventory version 2 # Project: foo # Version: 2.0 # The remainder of this file is compressed with zlib. -'''.encode() + zlib.compress('''\ +''' + zlib.compress(b'''\ module1 py:module 0 foo.html#module-module1 Long Module desc module2 py:module 0 foo.html#module-$ - module1.func py:function 1 sub/foo.html#$ - @@ -47,16 +47,16 @@ foo.bar js:class 1 index.html#foo.bar - foo.bar.baz js:method 1 index.html#foo.bar.baz - foo.bar.qux js:data 1 index.html#foo.bar.qux - a term including:colon std:term -1 glossary.html#term-a-term-including-colon - -'''.encode()) +''') -inventory_v2_not_having_version = '''\ +inventory_v2_not_having_version = b'''\ # Sphinx inventory version 2 # Project: foo # Version: # The remainder of this file is compressed with zlib. -'''.encode() + zlib.compress('''\ +''' + zlib.compress(b'''\ module1 py:module 0 foo.html#module-module1 Long Module desc -'''.encode()) +''') def test_read_inventory_v1(): diff --git a/tests/test_util_logging.py b/tests/test_util_logging.py index 36034cd92..aedbe9e64 100644 --- a/tests/test_util_logging.py +++ b/tests/test_util_logging.py @@ -4,7 +4,7 @@ Test logging util. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_util_matching.py b/tests/test_util_matching.py index 0a6bdc7b3..008dc6267 100644 --- a/tests/test_util_matching.py +++ b/tests/test_util_matching.py @@ -4,10 +4,10 @@ Tests sphinx.util.matching functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from sphinx.util.matching import compile_matchers, Matcher +from sphinx.util.matching import Matcher, compile_matchers def test_compile_matchers(): diff --git a/tests/test_util_nodes.py b/tests/test_util_nodes.py index 8fe9ee773..cb2ae70a8 100644 --- a/tests/test_util_nodes.py +++ b/tests/test_util_nodes.py @@ -4,22 +4,20 @@ Tests uti.nodes functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from textwrap import dedent from typing import Any import pytest -from docutils import frontend -from docutils import nodes +from docutils import frontend, nodes from docutils.parsers import rst from docutils.utils import new_document from sphinx.transforms import ApplySourceWorkaround -from sphinx.util.nodes import ( - NodeMatcher, extract_messages, clean_astext, make_id, split_explicit_title -) +from sphinx.util.nodes import (NodeMatcher, clean_astext, extract_messages, make_id, + split_explicit_title) def _transform(doctree): diff --git a/tests/test_util_pycompat.py b/tests/test_util_pycompat.py index 67e61bb58..0e395fa7a 100644 --- a/tests/test_util_pycompat.py +++ b/tests/test_util_pycompat.py @@ -4,7 +4,7 @@ Tests sphinx.util.pycompat functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_util_rst.py b/tests/test_util_rst.py index 6f55c5698..7e14eb3f7 100644 --- a/tests/test_util_rst.py +++ b/tests/test_util_rst.py @@ -4,16 +4,14 @@ Tests sphinx.util.rst functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from docutils.statemachine import StringList from jinja2 import Environment -from sphinx.util.rst import ( - append_epilog, escape, heading, prepend_prolog, textwidth -) +from sphinx.util.rst import append_epilog, escape, heading, prepend_prolog, textwidth def test_escape(): @@ -32,7 +30,7 @@ def test_append_epilog(app): assert list(content.xitems()) == [('dummy.rst', 0, 'hello Sphinx world'), ('dummy.rst', 1, 'Sphinx is a document generator'), - ('<generated>', 0, ''), + ('dummy.rst', 2, ''), ('<rst_epilog>', 0, 'this is rst_epilog'), ('<rst_epilog>', 1, 'good-bye reST!')] diff --git a/tests/test_util_template.py b/tests/test_util_template.py index 58ebd7fbb..bc325ac9d 100644 --- a/tests/test_util_template.py +++ b/tests/test_util_template.py @@ -4,7 +4,7 @@ Tests sphinx.util.template functions. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_util_typing.py b/tests/test_util_typing.py index 41d2a19c2..9da505814 100644 --- a/tests/test_util_typing.py +++ b/tests/test_util_typing.py @@ -4,17 +4,19 @@ Tests util.typing functions. - :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import sys from numbers import Integral -from typing import Any, Dict, List, TypeVar, Union, Callable, Tuple, Optional, Generic +from struct import Struct +from typing import (Any, Callable, Dict, Generator, List, NewType, Optional, Tuple, TypeVar, + Union) import pytest -from sphinx.util.typing import stringify +from sphinx.util.typing import restify, stringify class MyClass1: @@ -24,17 +26,107 @@ class MyClass1: class MyClass2(MyClass1): __qualname__ = '<MyClass2>' + T = TypeVar('T') +MyInt = NewType('MyInt', int) + class MyList(List[T]): pass +class BrokenType: + __args__ = int + + +def test_restify(): + assert restify(int) == ":class:`int`" + assert restify(str) == ":class:`str`" + assert restify(None) == ":obj:`None`" + assert restify(Integral) == ":class:`numbers.Integral`" + assert restify(Struct) == ":class:`struct.Struct`" + assert restify(Any) == ":obj:`Any`" + + +def test_restify_type_hints_containers(): + assert restify(List) == ":class:`List`" + assert restify(Dict) == ":class:`Dict`" + assert restify(List[int]) == ":class:`List`\\ [:class:`int`]" + assert restify(List[str]) == ":class:`List`\\ [:class:`str`]" + assert restify(Dict[str, float]) == ":class:`Dict`\\ [:class:`str`, :class:`float`]" + assert restify(Tuple[str, str, str]) == ":class:`Tuple`\\ [:class:`str`, :class:`str`, :class:`str`]" + assert restify(Tuple[str, ...]) == ":class:`Tuple`\\ [:class:`str`, ...]" + assert restify(List[Dict[str, Tuple]]) == ":class:`List`\\ [:class:`Dict`\\ [:class:`str`, :class:`Tuple`]]" + assert restify(MyList[Tuple[int, int]]) == ":class:`tests.test_util_typing.MyList`\\ [:class:`Tuple`\\ [:class:`int`, :class:`int`]]" + assert restify(Generator[None, None, None]) == ":class:`Generator`\\ [:obj:`None`, :obj:`None`, :obj:`None`]" + + +def test_restify_type_hints_Callable(): + assert restify(Callable) == ":class:`Callable`" + + if sys.version_info >= (3, 7): + assert restify(Callable[[str], int]) == ":class:`Callable`\\ [[:class:`str`], :class:`int`]" + assert restify(Callable[..., int]) == ":class:`Callable`\\ [[...], :class:`int`]" + else: + assert restify(Callable[[str], int]) == ":class:`Callable`\\ [:class:`str`, :class:`int`]" + assert restify(Callable[..., int]) == ":class:`Callable`\\ [..., :class:`int`]" + + +def test_restify_type_hints_Union(): + assert restify(Optional[int]) == ":obj:`Optional`\\ [:class:`int`]" + assert restify(Union[str, None]) == ":obj:`Optional`\\ [:class:`str`]" + assert restify(Union[int, str]) == ":obj:`Union`\\ [:class:`int`, :class:`str`]" + + if sys.version_info >= (3, 7): + assert restify(Union[int, Integral]) == ":obj:`Union`\\ [:class:`int`, :class:`numbers.Integral`]" + assert (restify(Union[MyClass1, MyClass2]) == + ":obj:`Union`\\ [:class:`tests.test_util_typing.MyClass1`, :class:`tests.test_util_typing.<MyClass2>`]") + else: + assert restify(Union[int, Integral]) == ":class:`numbers.Integral`" + assert restify(Union[MyClass1, MyClass2]) == ":class:`tests.test_util_typing.MyClass1`" + + +@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.') +def test_restify_type_hints_typevars(): + T = TypeVar('T') + T_co = TypeVar('T_co', covariant=True) + T_contra = TypeVar('T_contra', contravariant=True) + + assert restify(T) == ":obj:`tests.test_util_typing.T`" + assert restify(T_co) == ":obj:`tests.test_util_typing.T_co`" + assert restify(T_contra) == ":obj:`tests.test_util_typing.T_contra`" + assert restify(List[T]) == ":class:`List`\\ [:obj:`tests.test_util_typing.T`]" + assert restify(MyInt) == ":class:`MyInt`" + + +def test_restify_type_hints_custom_class(): + assert restify(MyClass1) == ":class:`tests.test_util_typing.MyClass1`" + assert restify(MyClass2) == ":class:`tests.test_util_typing.<MyClass2>`" + + +def test_restify_type_hints_alias(): + MyStr = str + MyTuple = Tuple[str, str] + assert restify(MyStr) == ":class:`str`" + assert restify(MyTuple) == ":class:`Tuple`\\ [:class:`str`, :class:`str`]" # type: ignore + + +@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.') +def test_restify_type_ForwardRef(): + from typing import ForwardRef # type: ignore + assert restify(ForwardRef("myint")) == ":class:`myint`" + + +def test_restify_broken_type_hints(): + assert restify(BrokenType) == ':class:`tests.test_util_typing.BrokenType`' + + def test_stringify(): assert stringify(int) == "int" assert stringify(str) == "str" assert stringify(None) == "None" assert stringify(Integral) == "numbers.Integral" + assert restify(Struct) == ":class:`struct.Struct`" assert stringify(Any) == "Any" @@ -47,13 +139,14 @@ def test_stringify_type_hints_containers(): assert stringify(Tuple[str, str, str]) == "Tuple[str, str, str]" assert stringify(Tuple[str, ...]) == "Tuple[str, ...]" assert stringify(List[Dict[str, Tuple]]) == "List[Dict[str, Tuple]]" - assert stringify(MyList[Tuple[int, int]]) == "test_util_typing.MyList[Tuple[int, int]]" + assert stringify(MyList[Tuple[int, int]]) == "tests.test_util_typing.MyList[Tuple[int, int]]" + assert stringify(Generator[None, None, None]) == "Generator[None, None, None]" @pytest.mark.skipif(sys.version_info < (3, 9), reason='python 3.9+ is required.') def test_stringify_Annotated(): - from typing import Annotated - assert stringify(Annotated[str, "foo", "bar"]) == "str" + from typing import Annotated # type: ignore + assert stringify(Annotated[str, "foo", "bar"]) == "str" # NOQA def test_stringify_type_hints_string(): @@ -83,10 +176,10 @@ def test_stringify_type_hints_Union(): if sys.version_info >= (3, 7): assert stringify(Union[int, Integral]) == "Union[int, numbers.Integral]" assert (stringify(Union[MyClass1, MyClass2]) == - "Union[test_util_typing.MyClass1, test_util_typing.<MyClass2>]") + "Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]") else: assert stringify(Union[int, Integral]) == "numbers.Integral" - assert stringify(Union[MyClass1, MyClass2]) == "test_util_typing.MyClass1" + assert stringify(Union[MyClass1, MyClass2]) == "tests.test_util_typing.MyClass1" def test_stringify_type_hints_typevars(): @@ -98,11 +191,12 @@ def test_stringify_type_hints_typevars(): assert stringify(T_co) == "T_co" assert stringify(T_contra) == "T_contra" assert stringify(List[T]) == "List[T]" + assert stringify(MyInt) == "MyInt" def test_stringify_type_hints_custom_class(): - assert stringify(MyClass1) == "test_util_typing.MyClass1" - assert stringify(MyClass2) == "test_util_typing.<MyClass2>" + assert stringify(MyClass1) == "tests.test_util_typing.MyClass1" + assert stringify(MyClass2) == "tests.test_util_typing.<MyClass2>" def test_stringify_type_hints_alias(): @@ -110,3 +204,7 @@ def test_stringify_type_hints_alias(): MyTuple = Tuple[str, str] assert stringify(MyStr) == "str" assert stringify(MyTuple) == "Tuple[str, str]" # type: ignore + + +def test_stringify_broken_type_hints(): + assert stringify(BrokenType) == 'tests.test_util_typing.BrokenType' diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 7fe3bce6f..33fb045ce 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -4,7 +4,7 @@ Test the versioning implementation. - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -15,8 +15,7 @@ from docutils.parsers.rst.directives.html import MetaBody from sphinx import addnodes from sphinx.testing.util import SphinxTestApp -from sphinx.versioning import add_uids, merge_doctrees, get_ratio - +from sphinx.versioning import add_uids, get_ratio, merge_doctrees app = original = original_uids = None diff --git a/tests/test_writer_latex.py b/tests/test_writer_latex.py index 160b14fa1..c3f6a622b 100644 --- a/tests/test_writer_latex.py +++ b/tests/test_writer_latex.py @@ -4,7 +4,7 @@ Test the LaTeX writer - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/typing_test_data.py b/tests/typing_test_data.py index 70c3144a0..c2db7d95b 100644 --- a/tests/typing_test_data.py +++ b/tests/typing_test_data.py @@ -1,5 +1,6 @@ +from inspect import Signature from numbers import Integral -from typing import Any, Dict, List, TypeVar, Union, Callable, Tuple, Optional +from typing import Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union def f0(x: int, y: Integral) -> None: @@ -76,7 +77,7 @@ def f14() -> Any: pass -def f15(x: "Unknown", y: "int") -> Any: +def f15(x: "Unknown", y: "int") -> Any: # type: ignore # NOQA pass @@ -100,6 +101,9 @@ def f20() -> Optional[Union[int, str]]: pass +def f21(arg1='whatever', arg2=Signature.empty): + pass + class Node: def __init__(self, parent: Optional['Node']) -> None: diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 000000000..9430c9beb --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,49 @@ +import contextlib +import http.server +import pathlib +import ssl +import threading + +# Generated with: +# $ openssl req -new -x509 -days 3650 -nodes -out cert.pem \ +# -keyout cert.pem -addext "subjectAltName = DNS:localhost" +CERT_FILE = str(pathlib.Path(__file__).parent / "certs" / "cert.pem") + + +class HttpServerThread(threading.Thread): + def __init__(self, handler, *args, **kwargs): + super().__init__(*args, **kwargs) + self.server = http.server.HTTPServer(("localhost", 7777), handler) + + def run(self): + self.server.serve_forever(poll_interval=0.01) + + def terminate(self): + self.server.shutdown() + self.server.server_close() + self.join() + + +class HttpsServerThread(HttpServerThread): + def __init__(self, handler, *args, **kwargs): + super().__init__(handler, *args, **kwargs) + self.server.socket = ssl.wrap_socket( + self.server.socket, + certfile=CERT_FILE, + server_side=True, + ) + + +def create_server(thread_class): + def server(handler): + server_thread = thread_class(handler, daemon=True) + server_thread.start() + try: + yield server_thread + finally: + server_thread.terminate() + return contextlib.contextmanager(server) + + +http_server = create_server(HttpServerThread) +https_server = create_server(HttpsServerThread) @@ -1,6 +1,6 @@ [tox] minversion = 2.4.0 -envlist = docs,flake8,mypy,coverage,py{35,36,37,38,39},du{12,13,14,15} +envlist = docs,flake8,mypy,twine,coverage,py{35,36,37,38,39},du{12,13,14,15} [testenv] usedevelop = True @@ -17,7 +17,6 @@ description = py{35,36,37,38,39}: Run unit tests against {envname}. du{12,13,14}: Run unit tests with the given version of docutils. deps = - git+https://github.com/html5lib/html5lib-python # refs: https://github.com/html5lib/html5lib-python/issues/419 du12: docutils==0.12 du13: docutils==0.13.1 du14: docutils==0.14 @@ -26,9 +25,10 @@ deps = extras = test setenv = - PYTHONWARNINGS = all,ignore::ImportWarning:importlib._bootstrap_external,ignore::DeprecationWarning:site,ignore::DeprecationWarning:distutils + PYTHONWARNINGS = all,ignore::ImportWarning:importlib._bootstrap_external,ignore::DeprecationWarning:site,ignore::DeprecationWarning:distutils,ignore::DeprecationWarning:pip._vendor.packaging.version + PYTEST_ADDOPTS = {env:PYTEST_ADDOPTS:} --color yes commands= - pytest --durations 25 {posargs} + python -X dev -m pytest --durations 25 {posargs} [testenv:flake8] basepython = python3 @@ -41,15 +41,16 @@ extras = commands = flake8 {posargs} -[testenv:pylint] +[testenv:isort] basepython = python3 description = - Run source code analyzer. -deps = - pylint - {[testenv]deps} + Run import sorting checks. +whitelist_externals = + isort +extras = + lint commands = - pylint --rcfile utils/pylintrc sphinx + isort --check-only --diff . [testenv:coverage] basepython = python3 @@ -88,6 +89,16 @@ extras = commands = python utils/doclinter.py CHANGES CONTRIBUTING.rst README.rst doc/ +[testenv:twine] +basepython = python3 +description = + Lint package. +deps = + twine +commands = + python setup.py release bdist_wheel sdist + twine check dist/* + [testenv:bindep] description = Install binary dependencies. diff --git a/utils/doclinter.py b/utils/doclinter.py index 52b2fe892..f8df20bf7 100644 --- a/utils/doclinter.py +++ b/utils/doclinter.py @@ -13,7 +13,6 @@ import re import sys from typing import List - MAX_LINE_LENGTH = 85 LONG_INTERPRETED_TEXT = re.compile(r'^\s*\W*(:(\w+:)+)?`.*`\W*$') CODE_BLOCK_DIRECTIVE = re.compile(r'^(\s*)\.\. code-block::') @@ -50,6 +49,9 @@ def lint(path: str) -> int: if re.match(r'^\s*\.\. ', line): # ignore directives and hyperlink targets pass + elif re.match(r'^\s*``[^`]+``$', line): + # ignore a very long literal string + pass else: print('%s:%d: the line is too long (%d > %d).' % (path, i + 1, len(line), MAX_LINE_LENGTH)) diff --git a/utils/pylintrc b/utils/pylintrc deleted file mode 100644 index cf71db595..000000000 --- a/utils/pylintrc +++ /dev/null @@ -1,301 +0,0 @@ -# lint Python modules using external checkers. -# -# This is the main checker controling the other ones and the reports -# generation. It is itself both a raw checker and an astng checker in order -# to: -# * handle message activation / deactivation at the module level -# * handle some basic but necessary stats'data (number of classes, methods...) -# -[MASTER] - -# Specify a configuration file. -#rcfile= - -# Profiled execution. -profile=no - -# Add <file or directory> to the black list. It should be a base name, not a -# path. You may set this option multiple times. -ignore=.svn - -# Pickle collected data for later comparisons. -persistent=yes - -# Set the cache size for astng objects. -cache-size=500 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - - -[MESSAGES CONTROL] - -# Enable only checker(s) with the given id(s). This option conflict with the -# disable-checker option -#enable-checker= - -# Enable all checker(s) except those with the given id(s). This option conflict -# with the disable-checker option -#disable-checker= - -# Enable all messages in the listed categories. -#enable-msg-cat= - -# Disable all messages in the listed categories. -#disable-msg-cat= - -# Enable the message(s) with the given id(s). -#enable-msg= - -# Disable the message(s) with the given id(s). -disable-msg=C0323,W0142,C0301,C0103,C0111,E0213,C0302,C0203,W0703,R0201,W0613,W0612,W0622 - - -[REPORTS] - -# set the output format. Available formats are text, parseable, colorized and -# html -output-format=colorized - -# Include message's id in output -include-ids=yes - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - -# Tells wether to display a full report or only the messages -reports=yes - -# Python expression which should return a note less than 10 (10 is the highest -# note).You have access to the variables errors warning, statement which -# respectivly contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (R0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Add a comment according to your evaluation note. This is used by the global -# evaluation report (R0004). -comment=no - -# Enable the report(s) with the given id(s). -#enable-report= - -# Disable the report(s) with the given id(s). -#disable-report= - - -# checks for -# * unused variables / imports -# * undefined variables -# * redefinition of variable from builtins or from an outer scope -# * use of variable before assigment -# -[VARIABLES] - -# Tells wether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching names used for dummy variables (i.e. not used). -dummy-variables-rgx=_|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - - -# try to find bugs in the code using type inference -# -[TYPECHECK] - -# Tells wether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# When zope mode is activated, consider the acquired-members option to ignore -# access to some undefined attributes. -zope=no - -# List of members which are usually get through zope's acquisition mecanism and -# so shouldn't trigger E0201 when accessed (need zope=yes to be considered). -acquired-members=REQUEST,acl_users,aq_parent - - -# checks for : -# * doc strings -# * modules / classes / functions / methods / arguments / variables name -# * number of arguments, local variables, branchs, returns and statements in -# functions, methods -# * required module attributes -# * dangerous default values as arguments -# * redefinition of function / method / class -# * uses of the global statement -# -[BASIC] - -# Required attributes for module, separated by a comma -required-attributes= - -# Regular expression which should only match functions or classes name which do -# not require a docstring -no-docstring-rgx=__.*__ - -# Regular expression which should only match correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression which should only match correct module level names -const-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__))$ - -# Regular expression which should only match correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression which should only match correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct instance attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct list comprehension / -# generator expression variable names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# List of builtins function names that should not be used, separated by a comma -bad-functions=apply,input - - -# checks for sign of poor/misdesign: -# * number of methods, attributes, local variables... -# * size, complexity of functions, methods -# -[DESIGN] - -# Maximum number of arguments for function / method -max-args=12 - -# Maximum number of locals for function / method body -max-locals=30 - -# Maximum number of return / yield for function / method body -max-returns=12 - -# Maximum number of branch for function / method body -max-branchs=30 - -# Maximum number of statements in function / method body -max-statements=60 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=20 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=0 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - - -# checks for -# * external modules dependencies -# * relative / wildcard imports -# * cyclic imports -# * uses of deprecated modules -# -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,string,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report R0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report R0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report R0402 must -# not be disabled) -int-import-graph= - - -# checks for : -# * methods without self as first argument -# * overridden methods signature -# * access only to existant members via self -# * attributes not defined in the __init__ method -# * supported interfaces implementation -# * unreachable code -# -[CLASSES] - -# List of interface methods to ignore, separated by a comma. This is used for -# instance to not check methods defines in Zope's Interface base class. -ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - - -# checks for similarities and duplicated code. This computation may be -# memory / CPU intensive, so you should disable it if you experiments some -# problems. -# -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=10 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - - -# checks for: -# * warning notes in the code -# * PEP 263: source code with non ascii character but no encoding declaration -# -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -# checks for : -# * unauthorized constructions -# * strict indentation -# * line length -# * use of <> instead of != -# -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=90 - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' diff --git a/utils/release-checklist b/utils/release-checklist index 5a60e59c8..477ddcbbe 100644 --- a/utils/release-checklist +++ b/utils/release-checklist @@ -4,14 +4,13 @@ Release checklist for stable releases ------------------- -* open https://travis-ci.org/sphinx-doc/sphinx/branches and check **X.Y** branch is green +* open "https://github.com/sphinx-doc/sphinx/actions?query=branch:X.Y.x" and all tests has passed * Run ``git fetch; git status`` and check nothing changed * ``python utils/bump_version.py X.Y.Z`` * Check diff by ``git diff`` * ``git commit -am 'Bump to X.Y.Z final'`` * ``make clean`` * ``python setup.py release bdist_wheel sdist`` -* ``twine check dist/Sphinx-*`` * ``twine upload dist/Sphinx-* --sign --identity [your GPG key]`` * open https://pypi.org/project/Sphinx/ and check there are no obvious errors * ``sh utils/bump_docker.sh X.Y.Z`` @@ -19,17 +18,17 @@ for stable releases * ``python utils/bump_version.py --in-develop X.Y.Zb0`` (ex. 1.5.3b0) * Check diff by ``git diff`` * ``git commit -am 'Bump version'`` -* ``git push origin X.Y --tags`` -* ``git checkout master`` -* ``git merge X.Y`` -* ``git push origin master`` +* ``git push origin X.Y.x --tags`` +* ``git checkout X.x`` +* ``git merge X.Y.x`` +* ``git push origin X.x`` * Add new version/milestone to tracker categories * Write announcement and send to sphinx-dev, sphinx-users and python-announce for first beta releases ----------------------- -* open https://travis-ci.org/sphinx-doc/sphinx/branches and check **master** branch is green +* open "https://github.com/sphinx-doc/sphinx/actions?query=branch:master" and all tests has passed * Run ``git fetch; git status`` and check nothing changed * Run ``python setup.py extract_messages`` * Run ``(cd sphinx/locale; tx push -s)`` @@ -38,17 +37,16 @@ for first beta releases * ``git commit -am 'Bump to X.Y.0 beta1'`` * ``make clean`` * ``python setup.py release bdist_wheel sdist`` -* ``twine check dist/Sphinx-*`` * ``twine upload dist/Sphinx-* --sign --identity [your GPG key]`` * open https://pypi.org/project/Sphinx/ and check there are no obvious errors * ``git tag vX.Y.0b1`` * ``python utils/bump_version.py --in-develop X.Y.0b2`` (ex. 1.6.0b2) * Check diff by ``git diff`` * ``git commit -am 'Bump version'`` -* ``git checkout -b X.Y`` -* ``git push origin X.Y --tags`` +* ``git checkout -b X.x`` +* ``git push origin X.x --tags`` * ``git checkout master`` -* ``git merge X.Y`` +* ``git merge X.x`` * ``python utils/bump_version.py --in-develop A.B.0b0`` (ex. 1.7.0b0) * Check diff by ``git diff`` * ``git commit -am 'Bump version'`` @@ -60,23 +58,22 @@ for first beta releases for other beta releases ----------------------- -* open https://travis-ci.org/sphinx-doc/sphinx/branches and check **X.Y** branch is green +* open "https://github.com/sphinx-doc/sphinx/actions?query=branch:X.x" and all tests has passed * Run ``git fetch; git status`` and check nothing changed * ``python utils/bump_version.py X.Y.0bN`` * Check diff by ``git diff`` * ``git commit -am 'Bump to X.Y.0 betaN'`` * ``make clean`` * ``python setup.py release bdist_wheel sdist`` -* ``twine check dist/Sphinx-*`` * ``twine upload dist/Sphinx-* --sign --identity [your GPG key]`` * open https://pypi.org/project/Sphinx/ and check there are no obvious errors * ``git tag vX.Y.0bN`` * ``python utils/bump_version.py --in-develop X.Y.0bM`` (ex. 1.6.0b3) * Check diff by `git diff`` * ``git commit -am 'Bump version'`` -* ``git push origin X.Y --tags`` +* ``git push origin X.x --tags`` * ``git checkout master`` -* ``git merge X.Y`` +* ``git merge X.x`` * ``git push origin master`` * Add new version/milestone to tracker categories * Write announcement and send to sphinx-dev, sphinx-users and python-announce @@ -84,7 +81,7 @@ for other beta releases for major releases ------------------ -* open https://travis-ci.org/sphinx-doc/sphinx/branches and check **X.Y** branch is green +* open "https://github.com/sphinx-doc/sphinx/actions?query=branch:X.x" and all tests has passed * Run ``git fetch; git status`` and check nothing changed * Run ``(cd sphinx/locale; tx pull -a -f)`` * Run ``python setup.py compile_catalog`` @@ -95,7 +92,6 @@ for major releases * ``git commit -am 'Bump to X.Y.0 final'`` * ``make clean`` * ``python setup.py release bdist_wheel sdist`` -* ``twine check dist/Sphinx-*`` * ``twine upload dist/Sphinx-* --sign --identity [your GPG key]`` * open https://pypi.org/project/Sphinx/ and check there are no obvious errors * ``sh utils/bump_docker.sh X.Y.Z`` @@ -103,9 +99,9 @@ for major releases * ``python utils/bump_version.py --in-develop X.Y.1b0`` (ex. 1.6.1b0) * Check diff by ``git diff`` * ``git commit -am 'Bump version'`` -* ``git push origin X.Y --tags`` +* ``git push origin X.x --tags`` * ``git checkout master`` -* ``git merge X.Y`` +* ``git merge X.x`` * ``git push origin master`` * open https://github.com/sphinx-doc/sphinx/settings/branches and make ``A.B`` branch *not* protected * ``git checkout A.B`` (checkout old stable) |