From 2124e238f82f5ca4e46027a5f4967c3f82fbcb80 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 22 Mar 2022 15:59:50 -0400 Subject: [PATCH 001/106] Bump to next micro.dev version --- src/sphobjinv/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sphobjinv/version.py b/src/sphobjinv/version.py index 1c7257a6..33537b3b 100644 --- a/src/sphobjinv/version.py +++ b/src/sphobjinv/version.py @@ -25,4 +25,4 @@ """ -__version__ = "2.2.2" +__version__ = "2.2.3.dev0" From 02fa433c0abdb05256bfee56603167d750a1062b Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 3 Jun 2022 23:14:22 -0400 Subject: [PATCH 002/106] Fix dead RtD link in suggest.rst --- doc/source/cli/suggest.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/source/cli/suggest.rst b/doc/source/cli/suggest.rst index d12a9026..5f2f7b8a 100644 --- a/doc/source/cli/suggest.rst +++ b/doc/source/cli/suggest.rst @@ -39,7 +39,7 @@ It is usually not necessary to locate the |objects.inv| file before running |soi for most Sphinx documentation sets, if you provide a URL to any page in the docs, it will automatically find and use the correct |objects.inv|: -.. command-output:: sphobjinv suggest -u https://sphobjinv.readthedocs.io/en/v2.0rc1/cmdline.html compress +.. command-output:: sphobjinv suggest -u https://sphobjinv.readthedocs.io/en/v2.0/cli/convert.html compress :cwd: /../../tests/resource |soi| only supports download of zlib-compressed |objects.inv| files by URL. @@ -105,6 +105,3 @@ If download of JSON files by URL is desirable, please Treat :option:`infile` as a URL for download. Cannot be used when :option:`infile` is passed as ``-``. - - - From 056e3d1456536c9cdb87defa1a54728c0bfb6426 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 00:08:01 -0400 Subject: [PATCH 003/106] Add tests for no/bad subparser CLI invocations. Covering the bases. Closes #239 --- tests/test_cli.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_cli.py b/tests/test_cli.py index 145cc1a9..03904999 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -74,6 +74,22 @@ def test_cli_noargs_shows_help(self, run_cmdline_test): assert "usage: sphobjinv" in out_.getvalue() + @pytest.mark.timeout(CLI_TEST_TIMEOUT) + def test_cli_no_subparser_prs_exit(self, run_cmdline_test): + """Confirm exit code 2 if option passed but no subparser provided.""" + with stdio_mgr() as (in_, out_, err_): + run_cmdline_test(["--foo"], expect=2) + + assert "required: {convert,suggest}" in err_.getvalue() + + @pytest.mark.timeout(CLI_TEST_TIMEOUT) + def test_cli_bad_subparser_prs_exit(self, run_cmdline_test): + """Confirm exit code 2 if invalid subparser provided.""" + with stdio_mgr() as (in_, out_, err_): + run_cmdline_test(["foo"], expect=2) + + assert "invalid choice: 'foo'" in err_.getvalue() + class TestConvertGood: """Tests for expected-good convert functionality.""" From 16185fbee57a60e12a45c277dee72e96b3fed43e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 00:02:53 -0400 Subject: [PATCH 004/106] Fix lint for unnecessary use of map in conftest Tuple comprehension definitely makes more sense here --- conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conftest.py b/conftest.py index 1ed15dd3..b1c40962 100644 --- a/conftest.py +++ b/conftest.py @@ -218,7 +218,7 @@ def sphinx_version(): """ p_version = re.compile(r"(\d+)[.]?(\d+)?[.]?(\d+)?") mch = p_version.match(sphinx_version_str) - return tuple(map((lambda x: int(x) if x else 0), mch.groups())) + return tuple(int(x) if x else 0 for x in mch.groups()) @pytest.fixture() # Must be function scope since uses monkeypatch From 2f258b9c57dd698572bad34897e6f6e6ec7fb784 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 00:02:35 -0400 Subject: [PATCH 005/106] Upgrade pre-commit version pin for black --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ff92ceda..ccc2af3c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: check-yaml - id: check-added-large-files - repo: https://github.com/psf/black - rev: '22.1.0' + rev: '22.3.0' hooks: - id: black - repo: https://github.com/tox-dev/pyproject-fmt From 749b9c9f86a8efa963f81318f19b978e02b54aed Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 09:16:44 -0400 Subject: [PATCH 006/106] Add trap for null subparser Also update corresponding test to match the actual error message. Closes #239 --- src/sphobjinv/cli/core.py | 4 ++++ tests/test_cli.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index 731f1f1a..a7303351 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -190,6 +190,10 @@ def main(): print(PrsConst.VER_TXT) sys.exit(0) + # At this point, need to trap for a null subparser + if not params[PrsConst.SUBPARSER_NAME]: + prs.error("No subparser selected") + # Regardless of mode, insert extra blank line # for cosmetics log_print(" ", params) diff --git a/tests/test_cli.py b/tests/test_cli.py index 03904999..99ba156f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -80,7 +80,7 @@ def test_cli_no_subparser_prs_exit(self, run_cmdline_test): with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["--foo"], expect=2) - assert "required: {convert,suggest}" in err_.getvalue() + assert "error: No subparser selected" in err_.getvalue() @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_bad_subparser_prs_exit(self, run_cmdline_test): From 6966311a3f348faa8daca295aecc5717e3a7368e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 09:20:07 -0400 Subject: [PATCH 007/106] Add CHANGELOG entry for null subparser fix --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5752032d..7dbce301 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project strives to adhere to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +### (unreleased) + +#### Fixed + + * CLI corner case where options are passed but no subparser is specified + now results in a clean error-exit, instead of an exception. + ([#239](https://github.com/bskinn/sphobjinv/issues/239)) + + ### [2.2.2] - 2022-03-22 #### Fixed From c5deb7f203304df1767259104421e8ea04449efc Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 09:46:34 -0400 Subject: [PATCH 008/106] Drop Windows pypy and 3.6 tests on Azure Pipelines Looks like Azure doesn't provide agents for them any more. --- azure-pipelines.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index da8b7654..893d0974 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -71,7 +71,7 @@ stages: spec: '3.10' pypy3: spec: 'pypy3' - platforms: [linux, windows] + platforms: [linux] - template: azure-coretest.yml parameters: @@ -84,7 +84,7 @@ stages: spec: '3.9' py310: spec: '3.10' - platforms: [macOs] + platforms: [windows, macOs] - stage: aux_tests @@ -203,5 +203,3 @@ stages: - script: tox -e flake8-noqa displayName: Run never-fail flake8 with noqa check - - From f37af66f8948ced5a7eeb62a786590e642b30fd1 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 10:08:28 -0400 Subject: [PATCH 009/106] Add Internal items to CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dbce301..2932d150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ and this project strives to adhere to now results in a clean error-exit, instead of an exception. ([#239](https://github.com/bskinn/sphobjinv/issues/239)) +#### Internal + + * Bump pre-commit black hook to v22.3.0 + + * Remove PyPy and Python 3.6 from Azure Pipelines test matrix + ### [2.2.2] - 2022-03-22 From 5b80b8ed0e90fbbc1bbcebc6e36e3c9b42712366 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 13:03:05 -0400 Subject: [PATCH 010/106] Expand verbosity of CLI suggest results count Closes #232 --- src/sphobjinv/cli/core.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index a7303351..f7f311f0 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -113,9 +113,25 @@ def do_suggest(inv, params): with_score=with_score, ) + log_print(f"{inv.count} objects in inventory.\n", params) + if len(results) == 0: - log_print("No results found.", params) + log_print( + ( + "No results found with score at/above current threshold of " + f"{params[PrsConst.THRESH]}." + ), + params, + ) return + else: + log_print( + ( + f"{len(results)} results found at/above current threshold of " + f"{params[PrsConst.THRESH]}.\n" + ), + params, + ) # Query if the results are long enough, but not if '--all' has been # passed or if the data is coming via stdin (reading from stdin breaks From d0a5b257bc5d3e3776e6402e7ab08489480b050e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 13:05:18 -0400 Subject: [PATCH 011/106] Add CHANGELOG entry for CLI suggest output changes --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2932d150..a85386be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,12 @@ and this project strives to adhere to ### [2.2.2] - 2022-03-22 +#### Changed + + * CLI 'suggest' results output now displays more information about + the total number of objects in the inventory, the search score threshold, + and the number of results falling at/above that threshold. + #### Fixed * UnicodeDecodeErrors are ignored within the vendored `fuzzywuzzy` package From dc54127c0b9752d2552a721d9d4741eda258d016 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 13:11:35 -0400 Subject: [PATCH 012/106] DOC: Remove bold from 'sphobjinv', blacken conf.py --- doc/source/conf.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index a532e35f..254089f3 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -17,9 +17,9 @@ # -- Project information ----------------------------------------------------- -project = 'sphobjinv' -copyright = '2016-2022, Brian Skinn' -author = 'Brian Skinn' +project = "sphobjinv" +copyright = "2016-2022, Brian Skinn" +author = "Brian Skinn" # The full version for `release`, including alpha/beta/rc tags from sphobjinv import __version__ as release @@ -51,7 +51,7 @@ issues_github_path = "bskinn/sphobjinv" # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -154,7 +154,7 @@ .. |soi| raw:: html - sphobjinv + sphobjinv .. |stdin| replace:: |cour|\ stdin\ |/cour| @@ -308,12 +308,12 @@ def file_head(fn, *, head=None): # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Output file basename htmlhelp_basename = "sphobjinv" From e90c1c65cccb054508fbac9f5eba152b2e04fb15 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 13:53:35 -0400 Subject: [PATCH 013/106] Update README and tests for new suggest output --- README.rst | 7 +++++++ tests/test_cli.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 641d13da..13130df8 100644 --- a/README.rst +++ b/README.rst @@ -56,6 +56,10 @@ For internal cross-references, locate ``objects.inv`` within ``build/html``:: $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 + 205 objects in inventory. + + 11 results found at/above current threshold of 58. + Name Score --------------------------------------------------- ------- :py:property:`sphobjinv.data.SuperDataObj.as_rst` 60 @@ -90,6 +94,9 @@ cross-reference the ``linspace`` function from numpy (see Attempting "https://numpy.org/doc/1.19/objects.inv" ... Remote inventory found. + 6487 objects in inventory. + + 8 results found at/above current threshold of 75. Name Score -------------------------------------------------------------- ------- diff --git a/tests/test_cli.py b/tests/test_cli.py index 99ba156f..8f3212d7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -340,7 +340,7 @@ def test_cli_suggest_noresults(self, run_cmdline_test, res_cmp): """Confirm suggest w/no found results works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-t", "99"]) - assert "No results found." in err_.getvalue() + assert "No results found" in err_.getvalue() @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_nameonly(self, run_cmdline_test, res_cmp): From bcf44c4dd0a009c743c1f6a3481be3807d787ed9 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 18:29:58 -0400 Subject: [PATCH 014/106] Add 'end' pass-thru to log_print Ended up not using 'end' in the end, but now it's there as a means to future ends, if that state of affairs ever comes to an end. --- src/sphobjinv/cli/ui.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sphobjinv/cli/ui.py b/src/sphobjinv/cli/ui.py index ee838e73..168a1a6c 100644 --- a/src/sphobjinv/cli/ui.py +++ b/src/sphobjinv/cli/ui.py @@ -30,8 +30,8 @@ from sphobjinv.cli.parser import PrsConst -def log_print(thing, params): - """Print `thing` to stderr if not in quiet mode. +def log_print(thing, params, *, end="\n"): + r"""Print `thing` to stderr if not in quiet mode. Quiet mode is indicated by the value at the |cli:QUIET| key within `params`. @@ -49,9 +49,13 @@ def log_print(thing, params): |dict| -- Parameters/values mapping from the active subparser + end + + |str| -- String to append to printed content (default: ``\n``\ ) + """ - if not params[PrsConst.SUBPARSER_NAME][:2] == "co" or not params[PrsConst.QUIET]: - print(thing, file=sys.stderr) + if params[PrsConst.SUBPARSER_NAME][:2] == "su" or not params[PrsConst.QUIET]: + print(thing, file=sys.stderr, end=end) def err_format(exc): From eec6c3e61c8d3df939882496349cbed2e0b12f0e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 18:31:32 -0400 Subject: [PATCH 015/106] Refactor URL inventory loading and add improved messages Closes #99. The messages will need to be changed/expanded/etc. once the exception hierarchy rework of #118 is done. --- src/sphobjinv/cli/load.py | 49 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/sphobjinv/cli/load.py b/src/sphobjinv/cli/load.py index 0a5d37cf..492b8771 100644 --- a/src/sphobjinv/cli/load.py +++ b/src/sphobjinv/cli/load.py @@ -156,33 +156,46 @@ def inv_url(params): """ in_file = params[PrsConst.INFILE] + def attempt_inv_load(url, params): + """Attempt the Inventory load and report outcome.""" + inv = None + + try: + inv = Inventory(url=url) + except HTTPError as e: + log_print(f" ... HTTP error: {e.code} {e.reason}.", params) + except URLError: + log_print(" ... error attempting to retrieve URL.", params) + except VersionError: + log_print(" ... no recognized inventory.", params) + except ValueError: + log_print( + ( + " ... file found but inventory could not be loaded. " + "(Did you forget https:// ?)" + ), + params, + ) + else: + log_print(" ... inventory found.", params) + + return inv + # Disallow --url mode on local files if in_file.startswith("file:/"): log_print("\nError: URL mode on local file is invalid", params) sys.exit(1) - # Need to initialize the inventory variable - inv = None + log_print(f"Attempting {in_file} ...", params) + inv = attempt_inv_load(in_file, params) - # Try URL as provided - try: - inv = Inventory(url=in_file) - except (HTTPError, ValueError, VersionError, URLError): - log_print("No inventory at provided URL.", params) - else: - log_print("Remote inventory found.", params) + if inv: url = in_file - - # Keep searching if inv not found yet - if not inv: + else: for url in urlwalk(in_file): log_print(f'Attempting "{url}" ...', params) - try: - inv = Inventory(url=url) - except (ValueError, HTTPError): - pass - else: - log_print("Remote inventory found.", params) + inv = attempt_inv_load(url, params) + if inv: break # Cosmetic line break From 867218c1e0b04074d68e75441b683b6045a538a9 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 18:34:09 -0400 Subject: [PATCH 016/106] Update tests and README with new suggest language. --- README.rst | 7 +++++-- tests/test_cli_nonlocal.py | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 13130df8..e02cd334 100644 --- a/README.rst +++ b/README.rst @@ -88,11 +88,14 @@ cross-reference the ``linspace`` function from numpy (see $ sphobjinv suggest https://numpy.org/doc/1.19/reference/index.html linspace -su - No inventory at provided URL. + Attempting https://numpy.org/doc/1.19/reference/index.html ... + ... no recognized inventory. Attempting "https://numpy.org/doc/1.19/reference/index.html/objects.inv" ... + ... HTTP error: 404 Not Found. Attempting "https://numpy.org/doc/1.19/reference/objects.inv" ... + ... HTTP error: 404 Not Found. Attempting "https://numpy.org/doc/1.19/objects.inv" ... - Remote inventory found. + ... inventory found. 6487 objects in inventory. diff --git a/tests/test_cli_nonlocal.py b/tests/test_cli_nonlocal.py index 6b0c78ed..01fa1f9a 100644 --- a/tests/test_cli_nonlocal.py +++ b/tests/test_cli_nonlocal.py @@ -123,7 +123,7 @@ def test_clifail_bad_url(self, run_cmdline_test, misc_info, scratch_path): ], expect=1, ) - assert "No inventory at provided URL." in err_.getvalue() + assert "HTTP error: 404 Not Found." in err_.getvalue() @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) def test_clifail_url_no_leading_http(self, run_cmdline_test, scratch_path): @@ -139,7 +139,7 @@ def test_clifail_url_no_leading_http(self, run_cmdline_test, scratch_path): ], expect=1, ) - assert "No inventory at provided URL." in err_.getvalue() + assert "file found but inventory could not be loaded" in err_.getvalue() def test_cli_json_export_import( self, res_cmp, scratch_path, misc_info, run_cmdline_test, sphinx_load_test From c5d742343903565a4db046e68801a8572aceba30 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 20:16:43 -0400 Subject: [PATCH 017/106] Fix doctest blocks in cli/convert.rst --- doc/source/cli/convert.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/source/cli/convert.rst b/doc/source/cli/convert.rst index d0ebc57d..caf15b77 100644 --- a/doc/source/cli/convert.rst +++ b/doc/source/cli/convert.rst @@ -66,7 +66,8 @@ indicated URL): >>> cli_run('sphobjinv convert plain -u https://github.com/bskinn/sphobjinv/raw/main/tests/resource/objects_attrs.inv') - Remote inventory found. + Attempting https://github.com/bskinn/sphobjinv/raw/main/tests/resource/objects_attrs.inv ... + ... inventory found. Conversion completed. 'https://github.com/b[...]ce/objects_attrs.inv' converted to '...objects.txt' (plain). @@ -91,11 +92,14 @@ it will automatically find and use the correct |objects.inv|: >>> cli_run('sphobjinv convert plain -ou https://docs.python.org/3/library/urllib.error.html#urllib.error.URLError') - No inventory at provided URL. + Attempting https://docs.python.org/3/library/urllib.error.html#urllib.error.URLError ... + ... no recognized inventory. Attempting "https://docs.python.org/3/library/urllib.error.html/objects.inv" ... + ... HTTP error: 404 Not Found. Attempting "https://docs.python.org/3/library/objects.inv" ... + ... HTTP error: 404 Not Found. Attempting "https://docs.python.org/3/objects.inv" ... - Remote inventory found. + ... inventory found. Conversion completed. '...objects.inv' converted to '...objects.txt' (plain). @@ -205,4 +209,3 @@ If processing of JSON files by API URL is desirable, please Contract `uri` and `dispname` fields, if possible, before writing to output; see :ref:`here `. Cannot be specified with :option:`--expand`. - From d3326fe274f3a079ad5b3ad00aea3ef02b0563a8 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 20:39:26 -0400 Subject: [PATCH 018/106] Add CHANGELOG entry --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a85386be..4f8b176b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project strives to adhere to ### (unreleased) +#### Added + + * The CLI now provides considerably more information about what is happening + with the URLs it checks when trying to retrieve a remote inventory. + ([#99](https://github.com/bskinn/sphobjinv/issues/99), plus more) + #### Fixed * CLI corner case where options are passed but no subparser is specified From 2427eca563992ff682356c27491c4d119bdee99e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 22:01:12 -0400 Subject: [PATCH 019/106] Add no cover for URLError inv_load case Not going to bother trying to introduce a network/hardware problem with urllib.request. --- src/sphobjinv/cli/load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sphobjinv/cli/load.py b/src/sphobjinv/cli/load.py index 492b8771..fa87f226 100644 --- a/src/sphobjinv/cli/load.py +++ b/src/sphobjinv/cli/load.py @@ -164,7 +164,7 @@ def attempt_inv_load(url, params): inv = Inventory(url=url) except HTTPError as e: log_print(f" ... HTTP error: {e.code} {e.reason}.", params) - except URLError: + except URLError: # pragma: no cover log_print(" ... error attempting to retrieve URL.", params) except VersionError: log_print(" ... no recognized inventory.", params) From 595b7c21b82b1ba1a83ba0a3c4c18f8f6ce3a67d Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 20:25:22 -0400 Subject: [PATCH 020/106] Setup: Modernize to license_files and improve __version__ The old 'license_file' setup.cfg field is deprecated, with the list-based license_files now preferred. Fixed. Improved the retrieval of __version__ from within the package by using an intermediary namespace dict with exec, and recovering the retrieved value from that. --- setup.cfg | 4 ++-- setup.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/setup.cfg b/setup.cfg index ac61076f..f48600a9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,7 +8,8 @@ project_urls = Thank=https://twitter.com/btskinn Donate=https://github.com/sponsors/bskinn license = MIT License -license_file = LICENSE.txt +license_files = + LICENSE.txt platforms = any author = Brian Skinn author_email = bskinn@alum.mit.edu @@ -54,4 +55,3 @@ where = src [options.entry_points] console_scripts = sphobjinv=sphobjinv.cli.core:main - \ No newline at end of file diff --git a/setup.py b/setup.py index f2ead1be..f144ca89 100644 --- a/setup.py +++ b/setup.py @@ -5,8 +5,9 @@ NAME = "sphobjinv" -exec(Path("src", "sphobjinv", "version.py").read_text(encoding="utf-8")) - +exec_ns = {} +exec(Path("src", "sphobjinv", "version.py").read_text(encoding="utf-8"), exec_ns) +__version__ = exec_ns["__version__"] version_override = "2.2" From f8e56713e1ee0e18387e84e89edc7867b22e14bd Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 4 Jun 2022 22:44:15 -0400 Subject: [PATCH 021/106] Add CHANGELOG entries --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f8b176b..b9810c55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,9 +23,15 @@ and this project strives to adhere to #### Internal - * Bump pre-commit black hook to v22.3.0 + * Bump pre-commit black hook to v22.3.0. - * Remove PyPy and Python 3.6 from Azure Pipelines test matrix + * Remove PyPy and Python 3.6 from Azure Pipelines test matrix. + + * Revise `__version__` retrieval in `setup.py` to use an intermediate + dictionary with `exec()`. + + * Update `setup.cfg` to use `license_files`, instead of the deprecated + `license_file`. ### [2.2.2] - 2022-03-22 From 28f6fafbd5b46940407b0558d74e64c178ddc07a Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Wed, 8 Jun 2022 08:46:38 -0400 Subject: [PATCH 022/106] Update FUNDING.yml Remove Liberapay and Paypal funding links. --- .github/FUNDING.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index e6d2cf33..1968306d 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -6,7 +6,7 @@ open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: pypi/sphobjinv # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: bskinn # Replace with a single Liberapay username +liberapay: # bskinn # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username -custom: ['https://paypal.me/btskinn'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +custom: # ['https://paypal.me/btskinn'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From 7d21f6342702875da87392f2095ee546085ec97a Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 28 Jun 2022 00:13:26 -0400 Subject: [PATCH 023/106] Add Django inventory to tests/resource --- tests/resource/objects_django.inv | Bin 0 -> 95387 bytes tests/test_api_good.py | 4 ++++ 2 files changed, 4 insertions(+) create mode 100644 tests/resource/objects_django.inv diff --git a/tests/resource/objects_django.inv b/tests/resource/objects_django.inv new file mode 100644 index 0000000000000000000000000000000000000000..a965611b838b4b0c222eb2c10de989e50616bf55 GIT binary patch literal 95387 zcmV)AK*YZzAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkJYGH0? zZwezIR%LQ?X>V>iAT%y83L_v?Xk{RBWo=<;Ze(S0Aa78b#rNMXCQiPX<{x4c-q9h-E!kNvZ#AsPvM9;7kft>sk*9rX3g3+CtS8% z@rtMwW?;+&V;PjZm>At{NZ2q5W+=yur>^GguF2_TU; z&!Y`}A=hb4-hQRz^(@={uP6yQKl^l+lc$gJ_sJ^cB%Zv8@A=24BrFP&ioYocef-=1 zbvF5Mk(00>9)L?Beo2auCSH);xq2TT2uXY;b%~=0R9E>r!tKssshMIT11Ux zI7l>J1y3v&DGlR6snpNE=5%0A#D9e8noYwjZ{3t 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

cX#IwsUjSC`(z&hDGe?z`#gu>Hc>5zLPV%Vblt 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 z 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 F{1c&C-7NqB literal 0 HcmV?d00001 diff --git a/tests/test_api_good.py b/tests/test_api_good.py index 50099637..f11f5a13 100644 --- a/tests/test_api_good.py +++ b/tests/test_api_good.py @@ -572,6 +572,10 @@ def test_api_inventory_matches_sphinx_ifile( original_ifile_data ), fname + elif "django.inv" in fname: # pragma: no cover + # TODO: Refine this adjustment as a function of sphinx_version if needed + assert inv.count == 13 + sphinx_ifile_data_count(original_ifile_data), fname + else: assert inv.count == sphinx_ifile_data_count(original_ifile_data), fname From 9cbb75721abf2881073f6dcc91c0bfe214310210 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 10:17:05 -0400 Subject: [PATCH 024/106] Bump versions for checkout and setup-python Actions --- .github/workflows/ci_tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index f399d2ac..e6fd5bb2 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -10,10 +10,10 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v2 + uses: actions/checkout@v2.5 - name: Install Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4.3 with: python-version: '3.10' @@ -64,10 +64,10 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v2 + uses: actions/checkout@v2.5 - name: Install Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4.3 with: python-version: ${{ matrix.python }} From ed4eac8464fce4b1b223c82ca4997dac239664ea Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 10:21:59 -0400 Subject: [PATCH 025/106] Fix Action version bumps --- .github/workflows/ci_tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index e6fd5bb2..1dfcf34c 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -10,10 +10,10 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v2.5 + uses: actions/checkout@v3 - name: Install Python - uses: actions/setup-python@v4.3 + uses: actions/setup-python@v4 with: python-version: '3.10' @@ -64,10 +64,10 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v2.5 + uses: actions/checkout@v3 - name: Install Python - uses: actions/setup-python@v4.3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} From 8b4db721a4c5a04ac3ebf83d7fbcd485b2539298 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 10:35:52 -0400 Subject: [PATCH 026/106] Add pip caching --- .github/workflows/ci_tests.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 1dfcf34c..8abf86e8 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -16,6 +16,10 @@ jobs: uses: actions/setup-python@v4 with: python-version: '3.10' + cache: 'pip' + cache-dependency-path: | + /requirements-ci.txt + /requirements-flake8.txt - name: Update pip & setuptools run: python -m pip install -U pip setuptools @@ -70,6 +74,10 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + cache: 'pip' + cache-dependency-path: | + /requirements-ci.txt + /requirements-flake8.txt - name: Update pip & setuptools run: python -m pip install -U pip setuptools From d2d6a1a1b7538b88a2fe990fcb2d0ead285fb751 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 10:37:33 -0400 Subject: [PATCH 027/106] Remove absolute path from reqts files --- .github/workflows/ci_tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 8abf86e8..f978e74c 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -18,8 +18,8 @@ jobs: python-version: '3.10' cache: 'pip' cache-dependency-path: | - /requirements-ci.txt - /requirements-flake8.txt + requirements-ci.txt + requirements-flake8.txt - name: Update pip & setuptools run: python -m pip install -U pip setuptools @@ -76,8 +76,8 @@ jobs: python-version: ${{ matrix.python }} cache: 'pip' cache-dependency-path: | - /requirements-ci.txt - /requirements-flake8.txt + requirements-ci.txt + requirements-flake8.txt - name: Update pip & setuptools run: python -m pip install -U pip setuptools From 03c9f6128ad8a5039d6d5c0d7bd217206e4a2a89 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 12 Jun 2022 23:09:10 -0400 Subject: [PATCH 028/106] Create POC for intersphinx inventory URL matching. Needs refactor, and then implementation of the actual construction of mappings. Squash history: (1) WIP: Exploring intersphinx mapping generation (2) Add more helpers and a couple of tests (3) Add (initial) working URL-compare function (4) Refactor matching obj check and add urlmatch test (5) Fix lints --- src/sphobjinv/__init__.py | 1 + src/sphobjinv/error.py | 20 ++++++++ src/sphobjinv/intersphinx.py | 89 ++++++++++++++++++++++++++++++++++++ tests/test_intersphinx.py | 81 ++++++++++++++++++++++++++++++++ tox.ini | 3 +- 5 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/sphobjinv/intersphinx.py create mode 100644 tests/test_intersphinx.py diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index bfdf67be..35709e0e 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -26,6 +26,7 @@ """ +from sphobjinv import intersphinx from sphobjinv.data import DataFields, DataObjBytes, DataObjStr from sphobjinv.enum import HeaderFields, SourceTypes from sphobjinv.error import SphobjinvError, VersionError diff --git a/src/sphobjinv/error.py b/src/sphobjinv/error.py index 6731d5cd..53e28e6a 100644 --- a/src/sphobjinv/error.py +++ b/src/sphobjinv/error.py @@ -37,3 +37,23 @@ class VersionError(SphobjinvError): |objects.inv| files (see :doc:`here `). """ + + # TODO: Add SOI prefix to this class name as part of the exceptions refactor + + +class SOIIntersphinxError(SphobjinvError): + """Family of errors from the sphobjinv.intersphinx module.""" + + +class SOIIsphxNotASuffixError(SOIIntersphinxError): + """Raised when a non-suffix URI is passed to the function matching.""" + + def __init__(self, *args, base, suffix, **kwargs): + """Initialize the instance with base and suffix strings.""" + super().__init__(*args, **kwargs) + self.base = base + self.suffix = suffix + + def __str__(self): + """Provide human-readable exception message.""" + return f"'{self.suffix}' is not a suffix of '{self.base}'" diff --git a/src/sphobjinv/intersphinx.py b/src/sphobjinv/intersphinx.py new file mode 100644 index 00000000..d35d5c91 --- /dev/null +++ b/src/sphobjinv/intersphinx.py @@ -0,0 +1,89 @@ +r"""``intersphinx`` *helpers for* ``sphobjinv``. + +``sphobjinv`` is a toolkit for manipulation and inspection of +Sphinx |objects.inv| files. + +**Author** + Brian Skinn (bskinn@alum.mit.edu) + +**File Created** + 12 Jun 2022 + +**Copyright** + \(c) Brian Skinn 2016-2022 + +**Source Repository** + https://github.com/bskinn/sphobjinv + +**Documentation** + https://sphobjinv.readthedocs.io/en/latest + +**License** + The MIT License; see |license_txt|_ for full license terms + +**Members** + +""" + +from urllib.parse import urlsplit + +from sphobjinv.error import SOIIsphxNotASuffixError + + +def _trim_url(url, *, with_scheme=False): + parts = urlsplit(url) + trimmed = f"{parts.netloc}{parts.path}" + + if with_scheme: + trimmed = f"{parts.scheme}://" + trimmed + + return trimmed + + +def _is_url_path_suffix(ref, candidate): + """Indicate whether the candidate path is a suffix of the ref.""" + return _trim_url(ref).endswith(_trim_url(candidate)) + + +def _obj_with_matching_uri(ref, inv): + """Provide an object in the invetory with a matching URI suffix. + + None if nothing found. + + """ + try: + return next(o for o in inv.objects if _is_url_path_suffix(ref, o.uri)) + except StopIteration: + return None + + +def _base_from_ref_and_suffix(ref, suffix): + url = _trim_url(ref, with_scheme=True) + + if not url.endswith(suffix): + raise SOIIsphxNotASuffixError(base=ref, suffix=suffix) + + # TODO: Once the project drops Python < 3.9, can reimplement with .removesuffix() + return url[: url.find(suffix)] + + +def _base_from_ref_and_object(ref, obj): + return _base_from_ref_and_suffix(ref, _trim_url(obj.uri)) + + +def _base_from_ref_and_matching_object(ref, inv): + work_obj = _obj_with_matching_uri(ref, inv) + return _base_from_ref_and_object(ref, work_obj) + + +def _trim_object_uri(uri): + return _trim_url(uri) + + +def _inventory_url_base(url): + return f"{urlsplit(url).scheme}://{_trim_url(url).rpartition('/')[0]}/" + + +def _url_matchup(web_url, obj_url, inv): + inventory_base = _inventory_url_base(obj_url) + return inventory_base == _base_from_ref_and_matching_object(web_url, inv) diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py new file mode 100644 index 00000000..523f91e3 --- /dev/null +++ b/tests/test_intersphinx.py @@ -0,0 +1,81 @@ +r"""*Tests for intersphinx-related functionality for* ``sphobjinv``. + +``sphobjinv`` is a toolkit for manipulation and inspection of +Sphinx |objects.inv| files. + +**Author** + Brian Skinn (bskinn@alum.mit.edu) + +**File Created** + 21 Jun 2022 + +**Copyright** + \(c) Brian Skinn 2016-2022 + +**Source Repository** + http://www.github.com/bskinn/sphobjinv + +**Documentation** + http://sphobjinv.readthedocs.io + +**License** + The MIT License; see |license_txt|_ for full license terms + +**Members** + +""" + +import pytest + +import sphobjinv as soi +import sphobjinv.intersphinx as soi_isphx + + +pytestmark = [pytest.mark.intersphinx] + + +@pytest.mark.local +@pytest.mark.parametrize( + ("uri", "trimmed"), + [("cli/implementation/parser.html#$", "cli/implementation/parser.html")], +) +def test_object_uri_trim(uri, trimmed): + """Confirm that object URI trimming is working.""" + assert trimmed == soi_isphx._trim_object_uri(uri) + + +@pytest.mark.local +@pytest.mark.parametrize( + ("url", "trimmed"), + [ + ( + "https://sphobjinv.readthedocs.io/en/latest/objects.inv", + "https://sphobjinv.readthedocs.io/en/latest/", + ) + ], +) +def test_inventory_url_trim(url, trimmed): + """Confirm that inventory URL trimming is working.""" + assert trimmed == soi_isphx._inventory_url_base(url) + + +@pytest.mark.nonloc +@pytest.mark.parametrize( + ("web_url", "inv_url", "result"), + [ + ( + ( + "https://sphobjinv.readthedocs.io/en/stable/api/" + "error.html#sphobjinv.error.VersionError" + ), + "https://sphobjinv.readthedocs.io/en/stable/objects.inv", + True, + ) + ], +) +def test_url_matchup(web_url, inv_url, result, pytestconfig): + """Confirm that URL matching works for known-good case.""" + if not pytestconfig.getoption("--nonloc"): + pytest.skip("'--nonloc' not specified") # pragma: no cover + + assert soi_isphx._url_matchup(web_url, inv_url, soi.Inventory(url=inv_url)) diff --git a/tox.ini b/tox.ini index 707cb204..424ce381 100644 --- a/tox.ini +++ b/tox.ini @@ -88,7 +88,7 @@ commands= skip_install=True deps=interrogate commands= - interrogate conftest.py tests src + interrogate {posargs} conftest.py tests src [testenv:sdist_install] commands= @@ -101,6 +101,7 @@ markers = nonloc: Tests requiring Internet access cli: Command-line interface tests api: Direct API tests + intersphinx: Tests on intersphinx-related functionality readme: Testing shell examples in README.rst fixture: Trivial tests for test suite fixtures testall: Tests that use *all* objects_xyz.inv files in tests/resource, if --testall is specified From 7a1e0326dab0a1dc084ef0acea08554dd8f4485d Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 25 Jun 2022 15:23:15 -0400 Subject: [PATCH 029/106] REFACTOR: Better names, leaner code, new test Rename a whole bunch of functions and parameters to make them more intuitive. Remove an interstitial function in the base-URL extraction code that was simple enough to just be folded into an enclosing function. Add a test looking at base URL matching for a locally stored inventory in tests/resource [skip ci] --- src/sphobjinv/error.py | 26 ++++++++++-- src/sphobjinv/intersphinx.py | 81 +++++++++++++++++++++--------------- tests/test_intersphinx.py | 34 +++++++++++++-- 3 files changed, 101 insertions(+), 40 deletions(-) diff --git a/src/sphobjinv/error.py b/src/sphobjinv/error.py index 53e28e6a..f58f7bc9 100644 --- a/src/sphobjinv/error.py +++ b/src/sphobjinv/error.py @@ -48,12 +48,32 @@ class SOIIntersphinxError(SphobjinvError): class SOIIsphxNotASuffixError(SOIIntersphinxError): """Raised when a non-suffix URI is passed to the function matching.""" - def __init__(self, *args, base, suffix, **kwargs): + def __init__(self, *args, web_url, suffix, **kwargs): """Initialize the instance with base and suffix strings.""" super().__init__(*args, **kwargs) - self.base = base + self.web_url = web_url self.suffix = suffix def __str__(self): """Provide human-readable exception message.""" - return f"'{self.suffix}' is not a suffix of '{self.base}'" + return f"'{self.suffix}' is not a suffix of '{self.web_url}'" + + +class SOIIsphxNoMatchingObjectError(SOIIntersphinxError): + """Raised when an Inventory does not have an object matching a reference URL. + + "Matching" here means that the object's URI is a suffix of the reference URL, + after both reference URL and suffix have their query and fragment components + removed. + + """ + + def __init__(self, *args, web_url, inv, **kwargs): + """Initialize the instance with reference URL and Inventory.""" + super().__init__(*args, **kwargs) + self.web_url = web_url + self.inv = inv + + def __str__(self): + """Provide human-readable exception message.""" + return f"'{self.inv}' does not have an object matching '{self.web_url}'" diff --git a/src/sphobjinv/intersphinx.py b/src/sphobjinv/intersphinx.py index d35d5c91..48cf479f 100644 --- a/src/sphobjinv/intersphinx.py +++ b/src/sphobjinv/intersphinx.py @@ -25,65 +25,80 @@ """ -from urllib.parse import urlsplit +from urllib import parse as urlparse -from sphobjinv.error import SOIIsphxNotASuffixError +from sphobjinv.error import SOIIsphxNoMatchingObjectError, SOIIsphxNotASuffixError -def _trim_url(url, *, with_scheme=False): - parts = urlsplit(url) - trimmed = f"{parts.netloc}{parts.path}" +def _strip_url_to_netloc_path(url, *, with_scheme=False): + """Reduce a URL to only netloc and path, optionally with scheme.""" + parts = urlparse.urlsplit(url) + trimmed = parts._replace( + query="", + fragment="", + ) - if with_scheme: - trimmed = f"{parts.scheme}://" + trimmed + if not with_scheme: + trimmed = trimmed._replace(scheme="") - return trimmed + return urlparse.urlunsplit(trimmed) -def _is_url_path_suffix(ref, candidate): - """Indicate whether the candidate path is a suffix of the ref.""" - return _trim_url(ref).endswith(_trim_url(candidate)) +def _extract_objectsinv_url_base(objectsinv_url): + """Provide the base URL for the provided objects.inv inventory URL.""" + trimmed = _strip_url_to_netloc_path(objectsinv_url, with_scheme=True) + return f"{trimmed.rpartition('/')[0]}/" -def _obj_with_matching_uri(ref, inv): - """Provide an object in the invetory with a matching URI suffix. +def _is_url_path_suffix(ref_url, suffix_candidate): + """Indicate whether the candidate path is a suffix of the reference URL.""" + return _strip_url_to_netloc_path(ref_url).endswith( + _strip_url_to_netloc_path(suffix_candidate) + ) - None if nothing found. + +def _find_obj_with_matching_uri(ref_url, inv): + """Provide an object from the inventory whose URI is a suffix of the reference URL. + + Returns None if nothing found. """ try: - return next(o for o in inv.objects if _is_url_path_suffix(ref, o.uri)) + return next(o for o in inv.objects if _is_url_path_suffix(ref_url, o.uri)) except StopIteration: return None -def _base_from_ref_and_suffix(ref, suffix): - url = _trim_url(ref, with_scheme=True) +def _extract_base_from_weburl_and_suffix(web_url, suffix): + """Extract the base URL from a reference web URL and the given suffix. - if not url.endswith(suffix): - raise SOIIsphxNotASuffixError(base=ref, suffix=suffix) + The base URL is returned **with** a trailing forward slash. - # TODO: Once the project drops Python < 3.9, can reimplement with .removesuffix() - return url[: url.find(suffix)] + Raises sphobjinv.error.SOIIsphxNotASuffixError if 'suffix' is + not actually a suffix of ref_url. + """ + trimmed = _strip_url_to_netloc_path(web_url, with_scheme=True) -def _base_from_ref_and_object(ref, obj): - return _base_from_ref_and_suffix(ref, _trim_url(obj.uri)) + if not trimmed.endswith(suffix): + raise SOIIsphxNotASuffixError(web_url=web_url, suffix=suffix) + # TODO: Once the project drops Python < 3.9, can reimplement with .removesuffix() + return trimmed[: trimmed.find(suffix)] -def _base_from_ref_and_matching_object(ref, inv): - work_obj = _obj_with_matching_uri(ref, inv) - return _base_from_ref_and_object(ref, work_obj) +def _extract_base_from_weburl_and_inventory(web_url, inv): + """Extract a candidate base URL from a docset web URL and an Inventory instance.""" + obj = _find_obj_with_matching_uri(web_url, inv) -def _trim_object_uri(uri): - return _trim_url(uri) + if obj is None: + raise SOIIsphxNoMatchingObjectError(web_url=web_url, inv=inv) + stripped_uri = _strip_url_to_netloc_path(obj.uri) -def _inventory_url_base(url): - return f"{urlsplit(url).scheme}://{_trim_url(url).rpartition('/')[0]}/" + return _extract_base_from_weburl_and_suffix(web_url, stripped_uri) -def _url_matchup(web_url, obj_url, inv): - inventory_base = _inventory_url_base(obj_url) - return inventory_base == _base_from_ref_and_matching_object(web_url, inv) +def _url_matchup(web_url, objectsinv_url, inv): + objectsinv_base = _extract_objectsinv_url_base(objectsinv_url) + return objectsinv_base == _extract_base_from_weburl_and_inventory(web_url, inv) diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 523f91e3..980e8b8a 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -41,7 +41,7 @@ ) def test_object_uri_trim(uri, trimmed): """Confirm that object URI trimming is working.""" - assert trimmed == soi_isphx._trim_object_uri(uri) + assert trimmed == soi_isphx._strip_url_to_netloc_path(uri) @pytest.mark.local @@ -56,7 +56,31 @@ def test_object_uri_trim(uri, trimmed): ) def test_inventory_url_trim(url, trimmed): """Confirm that inventory URL trimming is working.""" - assert trimmed == soi_isphx._inventory_url_base(url) + assert trimmed == soi_isphx._extract_objectsinv_url_base(url) + + +@pytest.mark.parametrize( + ("web_url", "inv_url", "result", "project"), + [ + ( + "https://www.attrs.org/en/17.2.0/api.html#attr.s", + "https://www.attrs.org/en/17.2.0/objects.inv", + True, + "attrs", + ) + ], +) +def test_url_matchup_local(web_url, inv_url, result, project, res_path): + """Confirm that URL matching works for selected test/resource inventories. + + These test(s) should continue to pass even if the various documentation sets + on the web are taken down. ``web_url`` and ``inv_url`` are chosen to be + valid and consistent with the versions of the |objects.inv| files stored + in ``tests/resource/`` + + """ + inv_path = res_path / f"objects_{project}.inv" + assert result == soi_isphx._url_matchup(web_url, inv_url, soi.Inventory(inv_path)) @pytest.mark.nonloc @@ -73,9 +97,11 @@ def test_inventory_url_trim(url, trimmed): ) ], ) -def test_url_matchup(web_url, inv_url, result, pytestconfig): +def test_url_matchup_nonloc(web_url, inv_url, result, pytestconfig): """Confirm that URL matching works for known-good case.""" if not pytestconfig.getoption("--nonloc"): pytest.skip("'--nonloc' not specified") # pragma: no cover - assert soi_isphx._url_matchup(web_url, inv_url, soi.Inventory(url=inv_url)) + assert result == soi_isphx._url_matchup( + web_url, inv_url, soi.Inventory(url=inv_url) + ) From b676783653651a357ad8fbecaf5cdadd3533f7e8 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 25 Jun 2022 21:33:02 -0400 Subject: [PATCH 030/106] Remove nonloc inventory base URL check test Fragile to future changes in the sphobjinv documentation, and a nonlocal test isn't needed here. Remove that nonlocal test, and then remark all tests in test_intersphinx.py as local. [skip ci] --- tests/test_intersphinx.py | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 980e8b8a..10811073 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -31,10 +31,9 @@ import sphobjinv.intersphinx as soi_isphx -pytestmark = [pytest.mark.intersphinx] +pytestmark = [pytest.mark.intersphinx, pytest.mark.local] -@pytest.mark.local @pytest.mark.parametrize( ("uri", "trimmed"), [("cli/implementation/parser.html#$", "cli/implementation/parser.html")], @@ -44,7 +43,6 @@ def test_object_uri_trim(uri, trimmed): assert trimmed == soi_isphx._strip_url_to_netloc_path(uri) -@pytest.mark.local @pytest.mark.parametrize( ("url", "trimmed"), [ @@ -76,32 +74,8 @@ def test_url_matchup_local(web_url, inv_url, result, project, res_path): These test(s) should continue to pass even if the various documentation sets on the web are taken down. ``web_url`` and ``inv_url`` are chosen to be valid and consistent with the versions of the |objects.inv| files stored - in ``tests/resource/`` + in ``tests/resource/``. """ inv_path = res_path / f"objects_{project}.inv" assert result == soi_isphx._url_matchup(web_url, inv_url, soi.Inventory(inv_path)) - - -@pytest.mark.nonloc -@pytest.mark.parametrize( - ("web_url", "inv_url", "result"), - [ - ( - ( - "https://sphobjinv.readthedocs.io/en/stable/api/" - "error.html#sphobjinv.error.VersionError" - ), - "https://sphobjinv.readthedocs.io/en/stable/objects.inv", - True, - ) - ], -) -def test_url_matchup_nonloc(web_url, inv_url, result, pytestconfig): - """Confirm that URL matching works for known-good case.""" - if not pytestconfig.getoption("--nonloc"): - pytest.skip("'--nonloc' not specified") # pragma: no cover - - assert result == soi_isphx._url_matchup( - web_url, inv_url, soi.Inventory(url=inv_url) - ) From 76fdf00b0388ed7108db2844e41f9f8a30c8778b Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 28 Jun 2022 00:12:13 -0400 Subject: [PATCH 031/106] Bump version to 2.3 dev --- README.rst | 6 +++--- src/sphobjinv/version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index e02cd334..c8411255 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,7 @@ For internal cross-references, locate ``objects.inv`` within ``build/html``:: $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 - 205 objects in inventory. + 208 objects in inventory. 11 results found at/above current threshold of 58. @@ -143,11 +143,11 @@ inventory creation/modification:: >>> import sphobjinv as soi >>> inv = soi.Inventory('doc/build/html/objects.inv') >>> print(inv) - + >>> inv.project 'sphobjinv' >>> inv.version - '2.2' + '2.3' >>> inv.objects[0] DataObjStr(name='sphobjinv.cli.core', domain='py', role='module', priority='0', uri='cli/implementation/core.html#module-$', dispname='-') diff --git a/src/sphobjinv/version.py b/src/sphobjinv/version.py index 33537b3b..211308cc 100644 --- a/src/sphobjinv/version.py +++ b/src/sphobjinv/version.py @@ -25,4 +25,4 @@ """ -__version__ = "2.2.3.dev0" +__version__ = "2.3.dev0" From 70b58d89e461e6a335f3762179fc71e2428b015a Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 28 Jun 2022 00:14:04 -0400 Subject: [PATCH 032/106] Implement mapping inference and add tests Test cases for Flask, Django, and NumPy at present. Will see if more end up needed. --- src/sphobjinv/intersphinx.py | 24 ++++++++++++++++++---- tests/test_intersphinx.py | 39 +++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/sphobjinv/intersphinx.py b/src/sphobjinv/intersphinx.py index 48cf479f..b37a6b20 100644 --- a/src/sphobjinv/intersphinx.py +++ b/src/sphobjinv/intersphinx.py @@ -45,9 +45,19 @@ def _strip_url_to_netloc_path(url, *, with_scheme=False): def _extract_objectsinv_url_base(objectsinv_url): - """Provide the base URL for the provided objects.inv inventory URL.""" + """Provide the base URL for the provided objects.inv inventory URL. + + # TODO: Convert this to a public API function + It should be useful as a fallback method of identifying a tentative + mapping for a docset, given the way that the urlwalk generator + steps through the possible objects.inv locations. + + If this function is a no-op, then the resulting base is NOT RELIABLE. + If this function *does* make a change, then the resulting base is + RELATIVELY RELIABLE. + """ trimmed = _strip_url_to_netloc_path(objectsinv_url, with_scheme=True) - return f"{trimmed.rpartition('/')[0]}/" + return f"{trimmed.rpartition('/objects.inv')[0]}/" def _is_url_path_suffix(ref_url, suffix_candidate): @@ -99,6 +109,12 @@ def _extract_base_from_weburl_and_inventory(web_url, inv): return _extract_base_from_weburl_and_suffix(web_url, stripped_uri) -def _url_matchup(web_url, objectsinv_url, inv): +def infer_mapping(web_url, objectsinv_url, inv): + """Infer a best-guess intersphinx_mapping entry for the given URLs and Inventory. + + # TODO: WRITE THIS DOCSTRING! + """ objectsinv_base = _extract_objectsinv_url_base(objectsinv_url) - return objectsinv_base == _extract_base_from_weburl_and_inventory(web_url, inv) + weburl_base = _extract_base_from_weburl_and_inventory(web_url, inv) + + return (weburl_base, None if objectsinv_base == weburl_base else objectsinv_url) diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 10811073..8039728d 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -58,24 +58,43 @@ def test_inventory_url_trim(url, trimmed): @pytest.mark.parametrize( - ("web_url", "inv_url", "result", "project"), + ("web_url", "inv_url", "project", "mapping"), [ ( - "https://www.attrs.org/en/17.2.0/api.html#attr.s", - "https://www.attrs.org/en/17.2.0/objects.inv", - True, - "attrs", - ) + "https://flask.palletsprojects.com/en/1.1.x/api/#flask.Config", + "https://flask.palletsprojects.com/en/1.1.x/objects.inv", + "flask", + ("https://flask.palletsprojects.com/en/1.1.x/", None), + ), + ( + "https://docs.djangoproject.com/en/4.0/topics/cache/#memcached", + "https://docs.djangoproject.com/en/4.0/_objects/", + "django", + ( + "https://docs.djangoproject.com/en/4.0/", + "https://docs.djangoproject.com/en/4.0/_objects/", + ), + ), + ( + ( + "https://docs.scipy.org/doc/numpy-1.13.0/reference/" + "arrays.interface.html#python-side" + ), + "https://docs.scipy.org/doc/numpy-1.13.0/objects.inv", + "numpy", + ("https://docs.scipy.org/doc/numpy-1.13.0/", None), + ), ], + ids=(lambda arg: arg if (isinstance(arg, str) and "/" not in arg) else ""), ) -def test_url_matchup_local(web_url, inv_url, result, project, res_path): - """Confirm that URL matching works for selected test/resource inventories. +def test_infer_mapping(web_url, inv_url, project, mapping, res_path): + """Confirm intersphinx mapping inference works for select test cases. These test(s) should continue to pass even if the various documentation sets on the web are taken down. ``web_url`` and ``inv_url`` are chosen to be valid and consistent with the versions of the |objects.inv| files stored - in ``tests/resource/``. + in the tests resource path `res_path`. """ inv_path = res_path / f"objects_{project}.inv" - assert result == soi_isphx._url_matchup(web_url, inv_url, soi.Inventory(inv_path)) + assert mapping == soi_isphx.infer_mapping(web_url, inv_url, soi.Inventory(inv_path)) From a2df05a5ce93095e33dafb7a3c2807361ca93a37 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 12 Jul 2022 20:28:19 -0400 Subject: [PATCH 033/106] Add *all* errors to __init__.py --- src/sphobjinv/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index 35709e0e..4942aa00 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -29,7 +29,13 @@ from sphobjinv import intersphinx from sphobjinv.data import DataFields, DataObjBytes, DataObjStr from sphobjinv.enum import HeaderFields, SourceTypes -from sphobjinv.error import SphobjinvError, VersionError +from sphobjinv.error import ( + SOIIntersphinxError, + SOIIsphxNoMatchingObjectError, + SOIIsphxNotASuffixError, + SphobjinvError, + VersionError, +) from sphobjinv.fileops import readbytes, readjson, urlwalk, writebytes, writejson from sphobjinv.inventory import Inventory from sphobjinv.re import p_data, pb_comments, pb_data, pb_project, pb_version From b6d6c845d4995ab9ebd9629b43531794871deea7 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 12 Jul 2022 20:28:55 -0400 Subject: [PATCH 034/106] Increase robustness of URL-object.uri matching Without this, a non-matching URI would *still match*, if the URI were either the empty string, or contained only a fragment (which reduced to the empty string, on simplification/stripping. --- src/sphobjinv/intersphinx.py | 8 +++++++- tests/test_intersphinx.py | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/sphobjinv/intersphinx.py b/src/sphobjinv/intersphinx.py index b37a6b20..d1deb018 100644 --- a/src/sphobjinv/intersphinx.py +++ b/src/sphobjinv/intersphinx.py @@ -74,7 +74,13 @@ def _find_obj_with_matching_uri(ref_url, inv): """ try: - return next(o for o in inv.objects if _is_url_path_suffix(ref_url, o.uri)) + return next( + o + for o in inv.objects + if o.uri # Must not be empty string + and not o.uri.startswith("#") # Must not only be a fragment + and _is_url_path_suffix(ref_url, o.uri) # Must be a suffix of the ref URL + ) except StopIteration: return None diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 8039728d..23be1e4e 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -98,3 +98,22 @@ def test_infer_mapping(web_url, inv_url, project, mapping, res_path): """ inv_path = res_path / f"objects_{project}.inv" assert mapping == soi_isphx.infer_mapping(web_url, inv_url, soi.Inventory(inv_path)) + + +@pytest.mark.parametrize( + ("web_url", "project"), + [ + ( + "https://docs.djangoproject.com/en/4.0/topicXYZs/cache/#memcached", + "django", + ) + ], + ids=(lambda arg: arg if (isinstance(arg, str) and "/" not in arg) else ""), +) +def test_no_matching_object(web_url, project, res_path): + """Confirm that no matching Inventory object is found when there shouldn't be.""" + inv_path = res_path / f"objects_{project}.inv" + with pytest.raises(soi.error.SOIIsphxNoMatchingObjectError): + soi_isphx._extract_base_from_weburl_and_inventory( + web_url, soi.Inventory(inv_path) + ) From 69b2d719382c58c42957a135e4088bc5bc539982 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 18:16:29 -0400 Subject: [PATCH 035/106] Make entire intersphinx.py private API for this may be YAGNI. We'll see. --- src/sphobjinv/__init__.py | 1 - src/sphobjinv/{intersphinx.py => _intersphinx.py} | 0 2 files changed, 1 deletion(-) rename src/sphobjinv/{intersphinx.py => _intersphinx.py} (100%) diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index 4942aa00..32cf1f34 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -26,7 +26,6 @@ """ -from sphobjinv import intersphinx from sphobjinv.data import DataFields, DataObjBytes, DataObjStr from sphobjinv.enum import HeaderFields, SourceTypes from sphobjinv.error import ( diff --git a/src/sphobjinv/intersphinx.py b/src/sphobjinv/_intersphinx.py similarity index 100% rename from src/sphobjinv/intersphinx.py rename to src/sphobjinv/_intersphinx.py From b8d9b83e589168509ba1b2069895153c85f895c6 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 18:20:55 -0400 Subject: [PATCH 036/106] Convert base-finder to public and add docstrings Also rename some intersphinx tests to more intuitive things, and add a couple of test cases for test_strip_netloc_path --- src/sphobjinv/__init__.py | 2 +- src/sphobjinv/_intersphinx.py | 89 ++++++++++++++++++++++++++--------- src/sphobjinv/error.py | 8 ++-- tests/test_api_fail.py | 2 +- tests/test_intersphinx.py | 34 +++++++++---- 5 files changed, 98 insertions(+), 37 deletions(-) diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index 32cf1f34..432076d8 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -31,7 +31,7 @@ from sphobjinv.error import ( SOIIntersphinxError, SOIIsphxNoMatchingObjectError, - SOIIsphxNotASuffixError, + SOIIsphxURINotASuffixError, SphobjinvError, VersionError, ) diff --git a/src/sphobjinv/_intersphinx.py b/src/sphobjinv/_intersphinx.py index d1deb018..6336de21 100644 --- a/src/sphobjinv/_intersphinx.py +++ b/src/sphobjinv/_intersphinx.py @@ -3,6 +3,11 @@ ``sphobjinv`` is a toolkit for manipulation and inspection of Sphinx |objects.inv| files. +This module is PRIVATE. The API details here may change without +warning. If you would like to be able to rely on these functions, +please open an issue describing your use-case: +https://github.com/bskinn/sphobjinv/issues + **Author** Brian Skinn (bskinn@alum.mit.edu) @@ -27,7 +32,7 @@ from urllib import parse as urlparse -from sphobjinv.error import SOIIsphxNoMatchingObjectError, SOIIsphxNotASuffixError +from sphobjinv.error import SOIIsphxNoMatchingObjectError, SOIIsphxURINotASuffixError def _strip_url_to_netloc_path(url, *, with_scheme=False): @@ -44,17 +49,30 @@ def _strip_url_to_netloc_path(url, *, with_scheme=False): return urlparse.urlunsplit(trimmed) -def _extract_objectsinv_url_base(objectsinv_url): - """Provide the base URL for the provided objects.inv inventory URL. +def extract_objectsinv_url_base(objectsinv_url): + """Infer a base URL for the provided ``objects.inv`` inventory URL. - # TODO: Convert this to a public API function - It should be useful as a fallback method of identifying a tentative - mapping for a docset, given the way that the urlwalk generator - steps through the possible objects.inv locations. + If this function is a no-op, then the resulting base is NOT RELIABLE, + because the URL did not end with ``/objects.inv``. - If this function is a no-op, then the resulting base is NOT RELIABLE. If this function *does* make a change, then the resulting base is - RELATIVELY RELIABLE. + RELATIVELY RELIABLE, since the only change that should occur is + stripping of a ``/objects.inv`` suffix, which strongly implies but + does not guarantee that the URL came from a Sphinx docset in the + standard multi-page HTML layout. + + Parameters + ---------- + objectsinv_url + + |str| -- URL from which to attempt docset base inference + + Returns + ------- + trimmed + + |str| -- URL after attempt to trim a trailing ``/objects.inv`` + """ trimmed = _strip_url_to_netloc_path(objectsinv_url, with_scheme=True) return f"{trimmed.rpartition('/objects.inv')[0]}/" @@ -62,6 +80,10 @@ def _extract_objectsinv_url_base(objectsinv_url): def _is_url_path_suffix(ref_url, suffix_candidate): """Indicate whether the candidate path is a suffix of the reference URL.""" + # We want any fragments/queries/parameters to be stripped off of BOTH + # the ref_url and the suffix_candidate. + # The scheme of the ref_url doesn't matter since we're only inspecting + # the end of the URL. return _strip_url_to_netloc_path(ref_url).endswith( _strip_url_to_netloc_path(suffix_candidate) ) @@ -70,7 +92,7 @@ def _is_url_path_suffix(ref_url, suffix_candidate): def _find_obj_with_matching_uri(ref_url, inv): """Provide an object from the inventory whose URI is a suffix of the reference URL. - Returns None if nothing found. + Returns ``None`` if nothing found. """ try: @@ -85,22 +107,22 @@ def _find_obj_with_matching_uri(ref_url, inv): return None -def _extract_base_from_weburl_and_suffix(web_url, suffix): - """Extract the base URL from a reference web URL and the given suffix. +def _extract_base_from_weburl_and_uri(web_url, uri): + """Extract the base URL from a reference web URL and the given URI. The base URL is returned **with** a trailing forward slash. - Raises sphobjinv.error.SOIIsphxNotASuffixError if 'suffix' is - not actually a suffix of ref_url. + Raises sphobjinv.error.SOIIsphxNotASuffixError if trimmed ``uri`` is + not actually a suffix of ``web_url``. """ - trimmed = _strip_url_to_netloc_path(web_url, with_scheme=True) + if not _is_url_path_suffix(web_url, uri): + raise SOIIsphxURINotASuffixError(web_url=web_url, uri=uri) - if not trimmed.endswith(suffix): - raise SOIIsphxNotASuffixError(web_url=web_url, suffix=suffix) + trimmed = _strip_url_to_netloc_path(web_url, with_scheme=True) # TODO: Once the project drops Python < 3.9, can reimplement with .removesuffix() - return trimmed[: trimmed.find(suffix)] + return trimmed[: trimmed.find(_strip_url_to_netloc_path(uri))] def _extract_base_from_weburl_and_inventory(web_url, inv): @@ -110,17 +132,38 @@ def _extract_base_from_weburl_and_inventory(web_url, inv): if obj is None: raise SOIIsphxNoMatchingObjectError(web_url=web_url, inv=inv) - stripped_uri = _strip_url_to_netloc_path(obj.uri) - - return _extract_base_from_weburl_and_suffix(web_url, stripped_uri) + return _extract_base_from_weburl_and_uri(web_url, obj.uri) def infer_mapping(web_url, objectsinv_url, inv): """Infer a best-guess intersphinx_mapping entry for the given URLs and Inventory. - # TODO: WRITE THIS DOCSTRING! + Parameters + ---------- + web_url + + str -- URL of a valid page (optionally with fragment) from a live docset + + objectsinv_url + + str -- URL of the ``objects.inv`` file for the live docset + + inv + + |Inventory| -- Instantiated inventory for the live docset---MAY be generated + from the ``objects.inv`` at `objectsinv_url`, but CAN be generated from + any ``objects.inv`` corresponding to the **same version** of the live docset + + + Returns + ------- + mapping + + (str, str or None) -- Inferred ``intersphinx_mapping`` entry + + """ - objectsinv_base = _extract_objectsinv_url_base(objectsinv_url) + objectsinv_base = extract_objectsinv_url_base(objectsinv_url) weburl_base = _extract_base_from_weburl_and_inventory(web_url, inv) return (weburl_base, None if objectsinv_base == weburl_base else objectsinv_url) diff --git a/src/sphobjinv/error.py b/src/sphobjinv/error.py index f58f7bc9..8fe48f18 100644 --- a/src/sphobjinv/error.py +++ b/src/sphobjinv/error.py @@ -45,18 +45,18 @@ class SOIIntersphinxError(SphobjinvError): """Family of errors from the sphobjinv.intersphinx module.""" -class SOIIsphxNotASuffixError(SOIIntersphinxError): +class SOIIsphxURINotASuffixError(SOIIntersphinxError): """Raised when a non-suffix URI is passed to the function matching.""" - def __init__(self, *args, web_url, suffix, **kwargs): + def __init__(self, *args, web_url, uri, **kwargs): """Initialize the instance with base and suffix strings.""" super().__init__(*args, **kwargs) self.web_url = web_url - self.suffix = suffix + self.uri = uri def __str__(self): """Provide human-readable exception message.""" - return f"'{self.suffix}' is not a suffix of '{self.web_url}'" + return f"'{self.uri}' is not a suffix of '{self.web_url}'" class SOIIsphxNoMatchingObjectError(SOIIntersphinxError): diff --git a/tests/test_api_fail.py b/tests/test_api_fail.py index 0dc975ad..4cf2e3a8 100644 --- a/tests/test_api_fail.py +++ b/tests/test_api_fail.py @@ -178,7 +178,7 @@ def test_apifail_inventory_no_object_invs(self, check): soi.Inventory(d) def test_apifail_compressed_inv_with_win_newlines(self, unix2dos, res_cmp): - """Confirm that a compressed inventory with Windows newlines does not decompress. + """Confirm that a compressed inventory with Windodddws newlines doesn't decompress. This should *never* happen, except in a pathological circumstance where unix2dos was specifically run on a compressed inventory. diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 23be1e4e..98224425 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -28,19 +28,37 @@ import pytest import sphobjinv as soi -import sphobjinv.intersphinx as soi_isphx +import sphobjinv._intersphinx as soi_isphx pytestmark = [pytest.mark.intersphinx, pytest.mark.local] @pytest.mark.parametrize( - ("uri", "trimmed"), - [("cli/implementation/parser.html#$", "cli/implementation/parser.html")], + ("uri", "trimmed", "with_scheme"), + [ + ("cli/implementation/parser.html#$", "cli/implementation/parser.html", False), + ( + ( + "https://sphobjinv.readthedocs.io/en/stable/api/" + "enum.html#sphobjinv.enum.HeaderFields" + ), + "//sphobjinv.readthedocs.io/en/stable/api/enum.html", + False, + ), + ( + ( + "https://sphobjinv.readthedocs.io/en/stable/api/" + "enum.html#sphobjinv.enum.HeaderFields" + ), + "https://sphobjinv.readthedocs.io/en/stable/api/enum.html", + True, + ), + ], ) -def test_object_uri_trim(uri, trimmed): +def test_strip_netloc_path(uri, trimmed, with_scheme): """Confirm that object URI trimming is working.""" - assert trimmed == soi_isphx._strip_url_to_netloc_path(uri) + assert trimmed == soi_isphx._strip_url_to_netloc_path(uri, with_scheme=with_scheme) @pytest.mark.parametrize( @@ -52,9 +70,9 @@ def test_object_uri_trim(uri, trimmed): ) ], ) -def test_inventory_url_trim(url, trimmed): +def test_extract_objinv_url_base(url, trimmed): """Confirm that inventory URL trimming is working.""" - assert trimmed == soi_isphx._extract_objectsinv_url_base(url) + assert trimmed == soi_isphx.extract_objectsinv_url_base(url) @pytest.mark.parametrize( @@ -113,7 +131,7 @@ def test_infer_mapping(web_url, inv_url, project, mapping, res_path): def test_no_matching_object(web_url, project, res_path): """Confirm that no matching Inventory object is found when there shouldn't be.""" inv_path = res_path / f"objects_{project}.inv" - with pytest.raises(soi.error.SOIIsphxNoMatchingObjectError): + with pytest.raises(soi.SOIIsphxNoMatchingObjectError): soi_isphx._extract_base_from_weburl_and_inventory( web_url, soi.Inventory(inv_path) ) From b10b06b2ee6d010d3456e7f7e42704370f621e28 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 18:29:18 -0400 Subject: [PATCH 037/106] Remove colorama/flake8 hack All of a sudden, it's making flake8 not fail the tox run, when it should,,,, --- tests/test_api_fail.py | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_api_fail.py b/tests/test_api_fail.py index 4cf2e3a8..aff99b11 100644 --- a/tests/test_api_fail.py +++ b/tests/test_api_fail.py @@ -178,7 +178,7 @@ def test_apifail_inventory_no_object_invs(self, check): soi.Inventory(d) def test_apifail_compressed_inv_with_win_newlines(self, unix2dos, res_cmp): - """Confirm that a compressed inventory with Windodddws newlines doesn't decompress. + """Confirm that a compressed inventory with Windows newlines doesn't decompress. This should *never* happen, except in a pathological circumstance where unix2dos was specifically run on a compressed inventory. diff --git a/tox.ini b/tox.ini index 424ce381..0028a6e0 100644 --- a/tox.ini +++ b/tox.ini @@ -75,7 +75,7 @@ basepython= skip_install=True deps=-rrequirements-flake8.txt commands= - python -c 'import sys, colorama; from flake8.main.cli import main; colorama.init(); sys.argv = ["flake8", "conftest.py", "tests", "src"]; main()' + flake8 conftest.py src tests [testenv:flake8-noqa] skip_install=True From 39b4753060b093658c4b2850dbc7bde6e1fb857a Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 18:36:06 -0400 Subject: [PATCH 038/106] Refactor CLI convert to new module --- src/sphobjinv/cli/convert.py | 69 ++++++++++++++++++++++++++++++++++++ src/sphobjinv/cli/core.py | 42 +--------------------- 2 files changed, 70 insertions(+), 41 deletions(-) create mode 100644 src/sphobjinv/cli/convert.py diff --git a/src/sphobjinv/cli/convert.py b/src/sphobjinv/cli/convert.py new file mode 100644 index 00000000..48c9f9b1 --- /dev/null +++ b/src/sphobjinv/cli/convert.py @@ -0,0 +1,69 @@ +r"""``sphobjinv`` *module for CLI convert functionality*. + +``sphobjinv`` is a toolkit for manipulation and inspection of +Sphinx |objects.inv| files. + +**Author** + Brian Skinn (bskinn@alum.mit.edu) + +**File Created** + 20 Oct 2022 + +**Copyright** + \(c) Brian Skinn 2016-2022 + +**Source Repository** + https://github.com/bskinn/sphobjinv + +**Documentation** + https://sphobjinv.readthedocs.io/en/latest + +**License** + The MIT License; see |license_txt|_ for full license terms + +**Members** + +""" + +from sphobjinv.cli.parser import PrsConst +from sphobjinv.cli.write import write_file, write_stdout + + +def do_convert(inv, in_path, params): + r"""Carry out the conversion operation, including writing output. + + If |cli:OVERWRITE| is passed and the output file + (the default location, or as passed to |cli:OUTFILE|) + exists, it will be overwritten without a prompt. Otherwise, + the user will be queried if it is desired to overwrite + the existing file. + + If |cli:QUIET| is passed, nothing will be + printed to |cour|\ stdout\ |/cour| + (potentially useful for scripting), + and any existing output file will be overwritten + without prompting. + + Parameters + ---------- + inv + + |Inventory| -- Inventory object to be output in the format + indicated by |cli:MODE|. + + in_path + + |str| -- For a local input file, its absolute path. + For a URL, the (possibly truncated) URL text. + + params + + |dict| -- Parameters/values mapping from the active subparser + + """ + if params[PrsConst.OUTFILE] == "-" or ( + params[PrsConst.INFILE] == "-" and params[PrsConst.OUTFILE] is None + ): + write_stdout(inv, params) + else: + write_file(inv, in_path, params) diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index f7f311f0..66a2a4c3 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -27,50 +27,10 @@ import sys +from sphobjinv.cli.convert import do_convert from sphobjinv.cli.load import inv_local, inv_stdin, inv_url from sphobjinv.cli.parser import getparser, PrsConst from sphobjinv.cli.ui import log_print, yesno_prompt -from sphobjinv.cli.write import write_file, write_stdout - - -def do_convert(inv, in_path, params): - r"""Carry out the conversion operation, including writing output. - - If |cli:OVERWRITE| is passed and the output file - (the default location, or as passed to |cli:OUTFILE|) - exists, it will be overwritten without a prompt. Otherwise, - the user will be queried if it is desired to overwrite - the existing file. - - If |cli:QUIET| is passed, nothing will be - printed to |cour|\ stdout\ |/cour| - (potentially useful for scripting), - and any existing output file will be overwritten - without prompting. - - Parameters - ---------- - inv - - |Inventory| -- Inventory object to be output in the format - indicated by |cli:MODE|. - - in_path - - |str| -- For a local input file, its absolute path. - For a URL, the (possibly truncated) URL text. - - params - - |dict| -- Parameters/values mapping from the active subparser - - """ - if params[PrsConst.OUTFILE] == "-" or ( - params[PrsConst.INFILE] == "-" and params[PrsConst.OUTFILE] is None - ): - write_stdout(inv, params) - else: - write_file(inv, in_path, params) def do_suggest(inv, params): From b21afa3ec93895567fa31b7e023131e658e51d96 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 18:41:32 -0400 Subject: [PATCH 039/106] Refactor CLI suggest to new module --- src/sphobjinv/cli/core.py | 108 +--------------------------- src/sphobjinv/cli/suggest.py | 136 +++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 106 deletions(-) create mode 100644 src/sphobjinv/cli/suggest.py diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index 66a2a4c3..fc4d5575 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -30,112 +30,8 @@ from sphobjinv.cli.convert import do_convert from sphobjinv.cli.load import inv_local, inv_stdin, inv_url from sphobjinv.cli.parser import getparser, PrsConst -from sphobjinv.cli.ui import log_print, yesno_prompt - - -def do_suggest(inv, params): - r"""Perform the suggest call and output the results. - - Results are printed one per line. - - If neither |cli:INDEX| nor |cli:SCORE| is specified, - the results are output without a header. - If either or both are specified, - the results are output in a lightweight tabular format. - - If the number of results exceeds - |cli:SUGGEST_CONFIRM_LENGTH|, - the user will be queried whether to display - all of the returned results - unless |cli:ALL| is specified. - - No |cli:QUIET| option is available here, since - a silent mode for suggestion output is nonsensical. - - Parameters - ---------- - inv - - |Inventory| -- Inventory object to be output in the format - indicated by |cli:MODE|. - - params - - |dict| -- Parameters/values mapping from the active subparser - - """ - with_index = params[PrsConst.INDEX] - with_score = params[PrsConst.SCORE] - results = inv.suggest( - params[PrsConst.SEARCH], - thresh=params[PrsConst.THRESH], - with_index=with_index, - with_score=with_score, - ) - - log_print(f"{inv.count} objects in inventory.\n", params) - - if len(results) == 0: - log_print( - ( - "No results found with score at/above current threshold of " - f"{params[PrsConst.THRESH]}." - ), - params, - ) - return - else: - log_print( - ( - f"{len(results)} results found at/above current threshold of " - f"{params[PrsConst.THRESH]}.\n" - ), - params, - ) - - # Query if the results are long enough, but not if '--all' has been - # passed or if the data is coming via stdin (reading from stdin breaks - # the terminal interactions) - if ( - len(results) > PrsConst.SUGGEST_CONFIRM_LENGTH - and not params[PrsConst.ALL] - and params[PrsConst.INFILE] != "-" - ): - resp = yesno_prompt(f"Display all {len(results)} results (Y/N)?") - if resp.lower() == "n": - log_print("\nExiting...", params) - sys.exit(0) - - # Field widths in output - score_width = 7 - index_width = 7 - - if with_index or with_score: - rst_width = max(len(res[0]) for res in results) - else: - rst_width = max(len(res) for res in results) - - rst_width += 2 - - if with_index: - if with_score: - fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}} {{2: ^{index_width}}}" - print(fmt.format(" Name", "Score", "Index")) - print(fmt.format("-" * rst_width, "-" * score_width, "-" * index_width)) - print("\n".join(fmt.format(*_) for _ in results)) - else: - fmt = f"{{0: <{rst_width}}} {{1: ^{index_width}}}" - print(fmt.format(" Name", "Index")) - print(fmt.format("-" * rst_width, "-" * index_width)) - print("\n".join(fmt.format(*_) for _ in results)) - else: - if with_score: - fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}}" - print(fmt.format(" Name", "Score")) - print(fmt.format("-" * rst_width, "-" * score_width)) - print("\n".join(fmt.format(*_) for _ in results)) - else: - print("\n".join(str(_) for _ in results)) +from sphobjinv.cli.suggest import do_suggest +from sphobjinv.cli.ui import log_print def main(): diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py new file mode 100644 index 00000000..8a93e57d --- /dev/null +++ b/src/sphobjinv/cli/suggest.py @@ -0,0 +1,136 @@ +r"""``sphobjinv`` *module for CLI suggest functionality*. + +``sphobjinv`` is a toolkit for manipulation and inspection of +Sphinx |objects.inv| files. + +**Author** + Brian Skinn (bskinn@alum.mit.edu) + +**File Created** + 20 Oct 2022 + +**Copyright** + \(c) Brian Skinn 2016-2022 + +**Source Repository** + https://github.com/bskinn/sphobjinv + +**Documentation** + https://sphobjinv.readthedocs.io/en/latest + +**License** + The MIT License; see |license_txt|_ for full license terms + +**Members** + +""" + +import sys + +from sphobjinv.cli.parser import PrsConst +from sphobjinv.cli.ui import log_print, yesno_prompt + + +def do_suggest(inv, params): + r"""Perform the suggest call and output the results. + + Results are printed one per line. + + If neither |cli:INDEX| nor |cli:SCORE| is specified, + the results are output without a header. + If either or both are specified, + the results are output in a lightweight tabular format. + + If the number of results exceeds + |cli:SUGGEST_CONFIRM_LENGTH|, + the user will be queried whether to display + all of the returned results + unless |cli:ALL| is specified. + + No |cli:QUIET| option is available here, since + a silent mode for suggestion output is nonsensical. + + Parameters + ---------- + inv + + |Inventory| -- Inventory object to be output in the format + indicated by |cli:MODE|. + + params + + |dict| -- Parameters/values mapping from the active subparser + + """ + with_index = params[PrsConst.INDEX] + with_score = params[PrsConst.SCORE] + results = inv.suggest( + params[PrsConst.SEARCH], + thresh=params[PrsConst.THRESH], + with_index=with_index, + with_score=with_score, + ) + + log_print(f"{inv.count} objects in inventory.\n", params) + + if len(results) == 0: + log_print( + ( + "No results found with score at/above current threshold of " + f"{params[PrsConst.THRESH]}." + ), + params, + ) + return + else: + log_print( + ( + f"{len(results)} results found at/above current threshold of " + f"{params[PrsConst.THRESH]}.\n" + ), + params, + ) + + # Query if the results are long enough, but not if '--all' has been + # passed or if the data is coming via stdin (reading from stdin breaks + # the terminal interactions) + if ( + len(results) > PrsConst.SUGGEST_CONFIRM_LENGTH + and not params[PrsConst.ALL] + and params[PrsConst.INFILE] != "-" + ): + resp = yesno_prompt(f"Display all {len(results)} results (Y/N)?") + if resp.lower() == "n": + log_print("\nExiting...", params) + sys.exit(0) + + # Field widths in output + score_width = 7 + index_width = 7 + + if with_index or with_score: + rst_width = max(len(res[0]) for res in results) + else: + rst_width = max(len(res) for res in results) + + rst_width += 2 + + if with_index: + if with_score: + fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}} {{2: ^{index_width}}}" + print(fmt.format(" Name", "Score", "Index")) + print(fmt.format("-" * rst_width, "-" * score_width, "-" * index_width)) + print("\n".join(fmt.format(*_) for _ in results)) + else: + fmt = f"{{0: <{rst_width}}} {{1: ^{index_width}}}" + print(fmt.format(" Name", "Index")) + print(fmt.format("-" * rst_width, "-" * index_width)) + print("\n".join(fmt.format(*_) for _ in results)) + else: + if with_score: + fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}}" + print(fmt.format(" Name", "Score")) + print(fmt.format("-" * rst_width, "-" * score_width)) + print("\n".join(fmt.format(*_) for _ in results)) + else: + print("\n".join(str(_) for _ in results)) From b9c29db6c51e4fc045886a92a536bc9a0c47ec14 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 18:49:59 -0400 Subject: [PATCH 040/106] Fix number for suggest finding 1 object Closes #244. --- src/sphobjinv/cli/suggest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 8a93e57d..87177bae 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -85,7 +85,9 @@ def do_suggest(inv, params): else: log_print( ( - f"{len(results)} results found at/above current threshold of " + f"{len(results)} result" + f"{'' if len(results) == 1 else 's'}" + " found at/above current threshold of " f"{params[PrsConst.THRESH]}.\n" ), params, From 51aa8e2343d72713cac96de373594b985d1ab197 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 23:23:43 -0400 Subject: [PATCH 041/106] Add new CLI modules to CLI "API" docs --- doc/source/cli/implementation/convert.rst | 7 +++++++ doc/source/cli/implementation/index.rst | 6 ++++-- doc/source/cli/implementation/suggest.rst | 7 +++++++ src/sphobjinv/cli/core.py | 3 ++- 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 doc/source/cli/implementation/convert.rst create mode 100644 doc/source/cli/implementation/suggest.rst diff --git a/doc/source/cli/implementation/convert.rst b/doc/source/cli/implementation/convert.rst new file mode 100644 index 00000000..cd68000b --- /dev/null +++ b/doc/source/cli/implementation/convert.rst @@ -0,0 +1,7 @@ +.. Module API page for cli/convert.py + +sphobjinv.cli.convert +===================== + +.. automodule:: sphobjinv.cli.convert + :members: diff --git a/doc/source/cli/implementation/index.rst b/doc/source/cli/implementation/index.rst index 55946645..a174e6f3 100644 --- a/doc/source/cli/implementation/index.rst +++ b/doc/source/cli/implementation/index.rst @@ -6,12 +6,14 @@ sphobjinv.cli (non-API) .. toctree:: :maxdepth: 1 + convert core load parser paths + suggest ui write - -.. .. |argparse| replace:: :mod:`argparse` \ No newline at end of file + +.. .. |argparse| replace:: :mod:`argparse` diff --git a/doc/source/cli/implementation/suggest.rst b/doc/source/cli/implementation/suggest.rst new file mode 100644 index 00000000..3424d1b5 --- /dev/null +++ b/doc/source/cli/implementation/suggest.rst @@ -0,0 +1,7 @@ +.. Module API page for cli/suggest.py + +sphobjinv.cli.suggest +===================== + +.. automodule:: sphobjinv.cli.suggest + :members: diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index fc4d5575..4eeb7eb1 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -44,7 +44,8 @@ def main(): Creates the |Inventory| from the indicated source and method. - Invokes :func:`do_convert` or :func:`do_suggest` + Invokes :func:`~sphobjinv.cli.convert.do_convert` or + :func:`~sphobjinv.cli.suggest.do_suggest` per the subparser name stored in |cli:SUBPARSER_NAME|. """ From c25112fa27b6cfafc3903cb276f87a379de669a3 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 23:25:52 -0400 Subject: [PATCH 042/106] Update doctest cases in README --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index c8411255..313e2cee 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,7 @@ For internal cross-references, locate ``objects.inv`` within ``build/html``:: $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 - 208 objects in inventory. + 215 objects in inventory. 11 results found at/above current threshold of 58. @@ -143,13 +143,13 @@ inventory creation/modification:: >>> import sphobjinv as soi >>> inv = soi.Inventory('doc/build/html/objects.inv') >>> print(inv) - + >>> inv.project 'sphobjinv' >>> inv.version '2.3' >>> inv.objects[0] - DataObjStr(name='sphobjinv.cli.core', domain='py', role='module', priority='0', uri='cli/implementation/core.html#module-$', dispname='-') + DataObjStr(name='sphobjinv.cli.convert', domain='py', role='module', priority='0', uri='cli/implementation/convert.html#module-$', dispname='-') The API also enables straightforward re-export of an inventory, for subsequent use with ``intersphinx`` cross-references. From 289505f399e00235f05efc9df4d0c2718656e27c Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 23:26:58 -0400 Subject: [PATCH 043/106] Refactor CLI code - Rename `log_print` to `print_stderr` - Break suggest code into functions - Add TODO for the mapping inference code to be added shortly --- src/sphobjinv/cli/core.py | 12 ++++--- src/sphobjinv/cli/load.py | 30 ++++++++-------- src/sphobjinv/cli/suggest.py | 67 +++++++++++++++++++++++++++++------- src/sphobjinv/cli/ui.py | 2 +- src/sphobjinv/cli/write.py | 18 +++++----- 5 files changed, 86 insertions(+), 43 deletions(-) diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index 4eeb7eb1..08316fb6 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -31,7 +31,7 @@ from sphobjinv.cli.load import inv_local, inv_stdin, inv_url from sphobjinv.cli.parser import getparser, PrsConst from sphobjinv.cli.suggest import do_suggest -from sphobjinv.cli.ui import log_print +from sphobjinv.cli.ui import print_stderr def main(): @@ -53,9 +53,11 @@ def main(): if len(sys.argv) == 1: sys.argv.append("-h") - # Parse commandline arguments + # Parse commandline arguments, discarding any unknown ones + # I forget why I set it up to discard these, it might be + # more confusing than it's worth.... prs = getparser() - ns, args_left = prs.parse_known_args() + ns, _ = prs.parse_known_args() params = vars(ns) # Print version &c. and exit if indicated @@ -69,7 +71,7 @@ def main(): # Regardless of mode, insert extra blank line # for cosmetics - log_print(" ", params) + print_stderr(" ", params) # Generate the input Inventory based on --url or stdio or file. # These inventory-load functions should call @@ -91,7 +93,7 @@ def main(): do_suggest(inv, params) # Cosmetic final blank line - log_print(" ", params) + print_stderr(" ", params) # Clean exit sys.exit(0) diff --git a/src/sphobjinv/cli/load.py b/src/sphobjinv/cli/load.py index fa87f226..c5105cd3 100644 --- a/src/sphobjinv/cli/load.py +++ b/src/sphobjinv/cli/load.py @@ -35,7 +35,7 @@ from sphobjinv import Inventory, readjson, urlwalk, VersionError from sphobjinv.cli.parser import PrsConst from sphobjinv.cli.paths import resolve_inpath -from sphobjinv.cli.ui import err_format, log_print +from sphobjinv.cli.ui import err_format, print_stderr def import_infile(in_path): @@ -107,14 +107,14 @@ def inv_local(params): try: in_path = resolve_inpath(params[PrsConst.INFILE]) except Exception as e: - log_print("\nError while parsing input file path:", params) - log_print(err_format(e), params) + print_stderr("\nError while parsing input file path:", params) + print_stderr(err_format(e), params) sys.exit(1) # Attempt import inv = import_infile(in_path) if inv is None: - log_print("\nError: Unrecognized file format", params) + print_stderr("\nError: Unrecognized file format", params) sys.exit(1) return inv, in_path @@ -163,13 +163,13 @@ def attempt_inv_load(url, params): try: inv = Inventory(url=url) except HTTPError as e: - log_print(f" ... HTTP error: {e.code} {e.reason}.", params) + print_stderr(f" ... HTTP error: {e.code} {e.reason}.", params) except URLError: # pragma: no cover - log_print(" ... error attempting to retrieve URL.", params) + print_stderr(" ... error attempting to retrieve URL.", params) except VersionError: - log_print(" ... no recognized inventory.", params) + print_stderr(" ... no recognized inventory.", params) except ValueError: - log_print( + print_stderr( ( " ... file found but inventory could not be loaded. " "(Did you forget https:// ?)" @@ -177,33 +177,33 @@ def attempt_inv_load(url, params): params, ) else: - log_print(" ... inventory found.", params) + print_stderr(" ... inventory found.", params) return inv # Disallow --url mode on local files if in_file.startswith("file:/"): - log_print("\nError: URL mode on local file is invalid", params) + print_stderr("\nError: URL mode on local file is invalid", params) sys.exit(1) - log_print(f"Attempting {in_file} ...", params) + print_stderr(f"Attempting {in_file} ...", params) inv = attempt_inv_load(in_file, params) if inv: url = in_file else: for url in urlwalk(in_file): - log_print(f'Attempting "{url}" ...', params) + print_stderr(f'Attempting "{url}" ...', params) inv = attempt_inv_load(url, params) if inv: break # Cosmetic line break - log_print(" ", params) + print_stderr(" ", params) # Success or no? if not inv: - log_print("No inventory found!", params) + print_stderr("No inventory found!", params) sys.exit(1) params.update({PrsConst.FOUND_URL: url}) @@ -250,5 +250,5 @@ def inv_stdin(params): except (AttributeError, UnicodeEncodeError, TypeError): pass - log_print("Invalid plaintext or JSON inventory format.", params) + print_stderr("Invalid plaintext or JSON inventory format.", params) sys.exit(1) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 87177bae..709c0a42 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -28,7 +28,7 @@ import sys from sphobjinv.cli.parser import PrsConst -from sphobjinv.cli.ui import log_print, yesno_prompt +from sphobjinv.cli.ui import print_stderr, yesno_prompt def do_suggest(inv, params): @@ -71,19 +71,41 @@ def do_suggest(inv, params): with_score=with_score, ) - log_print(f"{inv.count} objects in inventory.\n", params) + print_stderr(f"{inv.count} objects in inventory.\n", params) + log_print_result_count(params, results) + + # TODO: Print inferred intersphinx_mapping + # - If input URL is the objinv URL and objinv base finder is a no-op, + # then can't infer mapping + # - If input URL is the objinv URL and objinv base finder IS NOT a no-op, + # then mapping inferred from objinv base finder and None is PROBABLY + # reliable. + # - If input URL is NOT the objinv URL and objinv base finder is a no-op, + # then SOMETHING WEIRD HAPPENED. + # - If input URL is NOT the objinv URL and objinv base find IS NOT a no-op, + # then mapping inferred from objinv base finder and None is STRONGLY + # reliable. + + # The confirmation query here is conditional; see the function docstring. + confirm_print_if_long_list(params, results) + + log_print_results_table(with_index, with_score, results) + + +def log_print_result_count(params, results): + """Report the count of found objects from the suggest search.""" if len(results) == 0: - log_print( + print_stderr( ( "No results found with score at/above current threshold of " f"{params[PrsConst.THRESH]}." ), params, ) - return + sys.exit(0) else: - log_print( + print_stderr( ( f"{len(results)} result" f"{'' if len(results) == 1 else 's'}" @@ -93,9 +115,17 @@ def do_suggest(inv, params): params, ) - # Query if the results are long enough, but not if '--all' has been - # passed or if the data is coming via stdin (reading from stdin breaks - # the terminal interactions) + +def confirm_print_if_long_list(params, results): + """Check if the results list is too long and query user if to proceed. + + Skip the check if ``--all`` has been passed. + + Also skip the check if receiving data from ``stdin``, as a stream + interaction here fouls the data flow...I forget exactly how. + + """ + if ( len(results) > PrsConst.SUGGEST_CONFIRM_LENGTH and not params[PrsConst.ALL] @@ -103,13 +133,20 @@ def do_suggest(inv, params): ): resp = yesno_prompt(f"Display all {len(results)} results (Y/N)?") if resp.lower() == "n": - log_print("\nExiting...", params) + print_stderr("\nExiting...", params) sys.exit(0) + +def log_print_results_table(with_index, with_score, results): + """Prepare and print the table of suggest search results.""" # Field widths in output score_width = 7 index_width = 7 + # This is necessary because the results are returned as a + # list[str] if neither index nor score is included; but are + # returned as a list[tuple[...]] if one or both of index/score + # is included. if with_index or with_score: rst_width = max(len(res[0]) for res in results) else: @@ -117,22 +154,26 @@ def do_suggest(inv, params): rst_width += 2 + # For now, in each case the formatting for each row is dynamically + # stored in `fmt`, and then `fmt` is used to actually format each row. + + # TODO: Consider replacing this with a *real* table formatting tool if with_index: if with_score: fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}} {{2: ^{index_width}}}" print(fmt.format(" Name", "Score", "Index")) print(fmt.format("-" * rst_width, "-" * score_width, "-" * index_width)) - print("\n".join(fmt.format(*_) for _ in results)) + print("\n".join(fmt.format(*res) for res in results)) else: fmt = f"{{0: <{rst_width}}} {{1: ^{index_width}}}" print(fmt.format(" Name", "Index")) print(fmt.format("-" * rst_width, "-" * index_width)) - print("\n".join(fmt.format(*_) for _ in results)) + print("\n".join(fmt.format(*res) for res in results)) else: if with_score: fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}}" print(fmt.format(" Name", "Score")) print(fmt.format("-" * rst_width, "-" * score_width)) - print("\n".join(fmt.format(*_) for _ in results)) + print("\n".join(fmt.format(*res) for res in results)) else: - print("\n".join(str(_) for _ in results)) + print("\n".join(str(res) for res in results)) diff --git a/src/sphobjinv/cli/ui.py b/src/sphobjinv/cli/ui.py index 168a1a6c..21ee6959 100644 --- a/src/sphobjinv/cli/ui.py +++ b/src/sphobjinv/cli/ui.py @@ -30,7 +30,7 @@ from sphobjinv.cli.parser import PrsConst -def log_print(thing, params, *, end="\n"): +def print_stderr(thing, params, *, end="\n"): r"""Print `thing` to stderr if not in quiet mode. Quiet mode is indicated by the value at the |cli:QUIET| key diff --git a/src/sphobjinv/cli/write.py b/src/sphobjinv/cli/write.py index e828c49f..45386395 100644 --- a/src/sphobjinv/cli/write.py +++ b/src/sphobjinv/cli/write.py @@ -31,7 +31,7 @@ from sphobjinv.cli.parser import PrsConst from sphobjinv.cli.paths import resolve_outpath -from sphobjinv.cli.ui import err_format, log_print, yesno_prompt +from sphobjinv.cli.ui import err_format, print_stderr, yesno_prompt from sphobjinv.fileops import writebytes, writejson from sphobjinv.zlib import compress @@ -193,7 +193,7 @@ def write_stdout(inv, params): print(json.dumps(json_dict)) else: - log_print("Error: Only plaintext and JSON can be emitted to stdout.", params) + print_stderr("Error: Only plaintext and JSON can be emitted to stdout.", params) sys.exit(1) @@ -229,15 +229,15 @@ def write_file(inv, in_path, params): out_path = resolve_outpath(params[PrsConst.OUTFILE], in_path, params) except Exception as e: # pragma: no cover # This may not actually be reachable except in exceptional situations - log_print("\nError while constructing output file path:", params) - log_print(err_format(e), params) + print_stderr("\nError while constructing output file path:", params) + print_stderr(err_format(e), params) sys.exit(1) # If exists, must handle overwrite if os.path.isfile(out_path) and not params[PrsConst.OVERWRITE]: if params[PrsConst.INFILE] == "-": # If reading from stdin, just alert and don't overwrite - log_print("\nFile exists. To overwrite, supply '-o'. Exiting...", params) + print_stderr("\nFile exists. To overwrite, supply '-o'. Exiting...", params) sys.exit(0) # This could be written w/o nesting via elif, but would be harder to read. else: @@ -245,7 +245,7 @@ def write_file(inv, in_path, params): # If not a stdin read, confirm overwrite; or, just clobber if QUIET resp = yesno_prompt("File exists. Overwrite (Y/N)? ") if resp.lower() == "n": - log_print("\nExiting...", params) + print_stderr("\nExiting...", params) sys.exit(0) # Write the output file @@ -267,12 +267,12 @@ def write_file(inv, in_path, params): if mode == PrsConst.JSON: write_json(inv, out_path, params) except Exception as e: - log_print("\nError during write of output file:", params) - log_print(err_format(e), params) + print_stderr("\nError during write of output file:", params) + print_stderr(err_format(e), params) sys.exit(1) # Report success, if not QUIET - log_print( + print_stderr( "Conversion completed.\n" f"'{in_path if in_path else 'stdin'}' converted to '{out_path}' ({mode}).", params, From 4e089f64f9cfb0a0e06f6c43af1403d974d60cca Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 20 Oct 2022 23:27:43 -0400 Subject: [PATCH 044/106] Edit/reflow some docs --- README.rst | 8 ++++---- doc/source/cli/suggest.rst | 3 ++- src/sphobjinv/cli/suggest.py | 1 - 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 313e2cee..1734f447 100644 --- a/README.rst +++ b/README.rst @@ -80,8 +80,8 @@ The ``-s`` argument in the above shell command indicates to print the ``fuzzywuzzy`` match score along with each search result, and ``-t 50`` changes the reporting threshold for the match score. -For external references, just find the API documentation wherever it lives on the web, -and pass ``sphobjinv suggest`` a URL from within the documentation set +For external references, just find the API documentation wherever it lives on +the web, and pass ``sphobjinv suggest`` a URL from within the documentation set with the ``--url/-u`` flag. For example, say I need to know how to cross-reference the ``linspace`` function from numpy (see `here `__):: @@ -114,8 +114,8 @@ cross-reference the ``linspace`` function from numpy (see .. end shell command -**NOTE** that the results from ``sphobjinv suggest`` are printed using the longer -*block directives*, whereas cross-references must be composed using the +**NOTE** that the results from ``sphobjinv suggest`` are printed using the +longer *block directives*, whereas cross-references must be composed using the *inline directives*. Thus, the above ``linspace()`` function must be cross-referenced as ``:func:`numpy.linspace```, **not** ``:function:`numpy.linspace```. diff --git a/doc/source/cli/suggest.rst b/doc/source/cli/suggest.rst index 5f2f7b8a..44ad03e4 100644 --- a/doc/source/cli/suggest.rst +++ b/doc/source/cli/suggest.rst @@ -67,7 +67,8 @@ If download of JSON files by URL is desirable, please Path (or URL, if :option:`--url` is specified) to file to be searched. If passed as ``-``, |soi| will attempt import of a plaintext or JSON - inventory from ``stdin`` (incompatible with :option:`--url`). + inventory from ``stdin``. This is incompatible with :option:`--url`, + and automatically enables :option:`--all`. .. option:: search diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 709c0a42..1aeea146 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -125,7 +125,6 @@ def confirm_print_if_long_list(params, results): interaction here fouls the data flow...I forget exactly how. """ - if ( len(results) > PrsConst.SUGGEST_CONFIRM_LENGTH and not params[PrsConst.ALL] From 1f64ab2e86e5319092165de774957d213781346d Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 11:37:47 -0400 Subject: [PATCH 045/106] Bump flake8 to >5 and update colorization --- requirements-flake8.txt | 3 +-- tox.ini | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/requirements-flake8.txt b/requirements-flake8.txt index 83d8350e..833ef9ee 100644 --- a/requirements-flake8.txt +++ b/requirements-flake8.txt @@ -1,11 +1,10 @@ colorama -flake8>=3.7 +flake8>=5 flake8-2020 flake8-absolute-import flake8-bandit flake8-bugbear flake8-builtins -flake8-colors flake8-comprehensions flake8-docstrings>=1.3.1 flake8-eradicate diff --git a/tox.ini b/tox.ini index 0028a6e0..51057a91 100644 --- a/tox.ini +++ b/tox.ini @@ -124,7 +124,7 @@ exclude = ignore = W503 show_source = True max_line_length = 88 -format = ${cyan}%(path)s${reset}:${yellow}%(row)d${reset}:${green}%(col)d${reset} ${red}(%(code)s)${reset} %(text)s +format = %(cyan)s%(path)s%(reset)s:%(yellow)s%(row)d%(reset)s:%(green)s%(col)d%(reset)s %(red)s(%(code)s)%(reset)s %(text)s rst-roles = attr, class, From c11b8b6a44bd6ed795c437239971ce5108d9ecfc Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 12:11:10 -0400 Subject: [PATCH 046/106] Bump dev Sphinx version to 5.3.0 Closes #249 --- requirements-ci.txt | 2 +- requirements-dev.txt | 2 +- requirements-rtd.txt | 2 +- tox.ini | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/requirements-ci.txt b/requirements-ci.txt index 7db3e2dd..3fc79e1f 100644 --- a/requirements-ci.txt +++ b/requirements-ci.txt @@ -10,7 +10,7 @@ pytest-check>=0.4 pytest-cov pytest-ordering pytest-timeout -sphinx==4.3.1 +sphinx==5.3.0 sphinx-issues sphinx-removed-in sphinx-rtd-theme diff --git a/requirements-dev.txt b/requirements-dev.txt index d0e2f11a..6667e62b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -15,7 +15,7 @@ pytest-ordering pytest-timeout restview rope -sphinx==4.3.1 +sphinx==5.3.0 sphinx-autobuild sphinx-issues sphinx-removed-in diff --git a/requirements-rtd.txt b/requirements-rtd.txt index 739e1e36..2195463a 100644 --- a/requirements-rtd.txt +++ b/requirements-rtd.txt @@ -1,5 +1,5 @@ attrs>=19.2 -sphinx==4.3.1 +sphinx==5.3.0 sphinx-issues sphinx-removed-in sphinx-rtd-theme diff --git a/tox.ini b/tox.ini index 51057a91..6ff6b857 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ isolated_build=True envlist= py3{6,7,8,9,10,11}-sphx_latest-attrs_latest-jsch_latest py310-sphx_dev-attrs_dev-jsch_dev - py310-sphx_{1_6_x,1_x,2_x,3_x,dev}-attrs_latest-jsch_latest + py310-sphx_{1_6_x,1_x,2_x,3_x,4_x,dev}-attrs_latest-jsch_latest py310-sphx_latest-attrs_{19_2,19_3,20_1,20_2,20_3,21_2,21_3,dev}-jsch_latest py310-sphx_latest-attrs_latest-jsch_{3_0,3_1,3_2,4_0,4_1,dev} py36-sphx_1_6_x-attrs_19_2-jsch_3_0 @@ -23,6 +23,7 @@ deps= sphx_1_x: sphinx<2 sphx_2_x: sphinx<3 sphx_3_x: sphinx<4 + sphx_4_x: sphinx<5 sphx_2_3_1: sphinx==2.3.1 sphx_2_4_0: sphinx==2.4.0 sphx_3_2_1: sphinx==3.2.1 @@ -134,6 +135,7 @@ rst-roles = func, meth, mod, + option, ref, rst-directives = doctest, From 856109265a947858ed549d53409d98ddf45df14b Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 23:17:15 -0400 Subject: [PATCH 047/106] Rename cli.suggest functions Now they're a bit more accurate --- src/sphobjinv/cli/suggest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 1aeea146..348b1aae 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -73,7 +73,7 @@ def do_suggest(inv, params): print_stderr(f"{inv.count} objects in inventory.\n", params) - log_print_result_count(params, results) + print_stderr_result_count(params, results) # TODO: Print inferred intersphinx_mapping # - If input URL is the objinv URL and objinv base finder is a no-op, @@ -90,10 +90,10 @@ def do_suggest(inv, params): # The confirmation query here is conditional; see the function docstring. confirm_print_if_long_list(params, results) - log_print_results_table(with_index, with_score, results) + print_results_table(with_index, with_score, results) -def log_print_result_count(params, results): +def print_stderr_result_count(params, results): """Report the count of found objects from the suggest search.""" if len(results) == 0: print_stderr( @@ -136,7 +136,7 @@ def confirm_print_if_long_list(params, results): sys.exit(0) -def log_print_results_table(with_index, with_score, results): +def print_results_table(with_index, with_score, results): """Prepare and print the table of suggest search results.""" # Field widths in output score_width = 7 From f43d7295bab46a84a4f4ef5f425c0f15783e76bf Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 23:54:12 -0400 Subject: [PATCH 048/106] Improve comments and add cosmetic newline --- src/sphobjinv/cli/suggest.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 348b1aae..74e9eb9e 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -87,7 +87,8 @@ def do_suggest(inv, params): # then mapping inferred from objinv base finder and None is STRONGLY # reliable. - # The confirmation query here is conditional; see the function docstring. + # The query here for printing the full list only occurs in some + # circumstances; see the function docstring. confirm_print_if_long_list(params, results) print_results_table(with_index, with_score, results) @@ -135,6 +136,9 @@ def confirm_print_if_long_list(params, results): print_stderr("\nExiting...", params) sys.exit(0) + # Extra cosmetic newline + print_stderr("", params) + def print_results_table(with_index, with_score, results): """Prepare and print the table of suggest search results.""" From 9cf540db018e9b4603b73eba3a7fb9e63390d92b Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 21 Oct 2022 23:54:46 -0400 Subject: [PATCH 049/106] Implement mapping inference Still need a couple of tests. Can base on sphobjinv's RtD docs, since I have control over what stays posted there. --- src/sphobjinv/cli/suggest.py | 74 ++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 74e9eb9e..21944d61 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -27,6 +27,7 @@ import sys +import sphobjinv._intersphinx as soi_isphx from sphobjinv.cli.parser import PrsConst from sphobjinv.cli.ui import print_stderr, yesno_prompt @@ -75,17 +76,7 @@ def do_suggest(inv, params): print_stderr_result_count(params, results) - # TODO: Print inferred intersphinx_mapping - # - If input URL is the objinv URL and objinv base finder is a no-op, - # then can't infer mapping - # - If input URL is the objinv URL and objinv base finder IS NOT a no-op, - # then mapping inferred from objinv base finder and None is PROBABLY - # reliable. - # - If input URL is NOT the objinv URL and objinv base finder is a no-op, - # then SOMETHING WEIRD HAPPENED. - # - If input URL is NOT the objinv URL and objinv base find IS NOT a no-op, - # then mapping inferred from objinv base finder and None is STRONGLY - # reliable. + print_stderr_inferred_mapping(params) # The query here for printing the full list only occurs in some # circumstances; see the function docstring. @@ -180,3 +171,64 @@ def print_results_table(with_index, with_score, results): print("\n".join(fmt.format(*res) for res in results)) else: print("\n".join(str(res) for res in results)) + + +def print_stderr_inferred_mapping(params): + """Print as good of an `intersphinx_mapping` entry as can be determined.""" + if not params[PrsConst.URL]: + print_stderr( + "Cannot infer intersphinx_mapping from a local objects.inv.\n", params + ) + return + + input_url = params[PrsConst.INFILE] + inv_url = params[PrsConst.FOUND_URL] + + reduced_inv_url = soi_isphx.extract_objectsinv_url_base(inv_url) + + if input_url == inv_url: + # User provided an exact URL to an inventory + # The tail of input_url thus should not match anything in the inventory, + # so we can't say anything about what the URL base of the docset is. + if inv_url == reduced_inv_url: + # The inventory URL does not end with the standard /objects.inv, + # so we don't even have *that* point of reference to work with. + print_stderr( + ( + "Cannot infer intersphinx_mapping for this docset using\n" + "the provided input URL.\n" + ), + params, + ) + else: + # The inventory URL *does* end with standard /objects.inv, + # so there's a reasonable chance we know the mapping. + print_stderr( + ( + "The intersphinx_mapping for this docset is PROBABLY:\n\n" + f" ({reduced_inv_url}, None)\n" + ), + params, + ) + else: + # User provided a URL from the docset that reduced to a base, atop which + # an inventory at .../objects.inv was found. + if inv_url == reduced_inv_url: + # This should never happen, because the only way we should be in + # this outer else is if inv_url *DOES* end in /objects.inv + print_stderr( + ( + "ERROR: Inconsistent internal state " + "during intersphinx_mapping inference.\n" + ), + params, + ) + else: + # Here we're *very* confident that we've go the mapping. + print_stderr( + ( + "The intersphinx_mapping for this docset is LIKELY:\n\n" + f" ({reduced_inv_url}, None)\n" + ), + params, + ) From 81d08b157c2d9d9ea6568435af3256dfb839d05b Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 22 Oct 2022 16:27:53 -0400 Subject: [PATCH 050/106] Refactor intersphinx code and add tests - Remove sphobjinv._intersphinx - Refactor still-needed functions to sphobjinv.cli.suggest - Add tests for the CLI mapping-inference output --- README.rst | 6 ++ src/sphobjinv/_intersphinx.py | 169 ---------------------------------- src/sphobjinv/cli/suggest.py | 47 +++++++++- tests/test_cli_nonlocal.py | 47 ++++++---- tests/test_intersphinx.py | 71 +------------- 5 files changed, 84 insertions(+), 256 deletions(-) delete mode 100644 src/sphobjinv/_intersphinx.py diff --git a/README.rst b/README.rst index 1734f447..3d438d4c 100644 --- a/README.rst +++ b/README.rst @@ -60,6 +60,8 @@ For internal cross-references, locate ``objects.inv`` within ``build/html``:: 11 results found at/above current threshold of 58. + Cannot infer intersphinx_mapping from a local objects.inv. + Name Score --------------------------------------------------- ------- :py:property:`sphobjinv.data.SuperDataObj.as_rst` 60 @@ -101,6 +103,10 @@ cross-reference the ``linspace`` function from numpy (see 8 results found at/above current threshold of 75. + The intersphinx_mapping for this docset is LIKELY: + + (https://numpy.org/doc/1.19/, None) + Name Score -------------------------------------------------------------- ------- :py:function:`numpy.linspace` 90 diff --git a/src/sphobjinv/_intersphinx.py b/src/sphobjinv/_intersphinx.py deleted file mode 100644 index 6336de21..00000000 --- a/src/sphobjinv/_intersphinx.py +++ /dev/null @@ -1,169 +0,0 @@ -r"""``intersphinx`` *helpers for* ``sphobjinv``. - -``sphobjinv`` is a toolkit for manipulation and inspection of -Sphinx |objects.inv| files. - -This module is PRIVATE. The API details here may change without -warning. If you would like to be able to rely on these functions, -please open an issue describing your use-case: -https://github.com/bskinn/sphobjinv/issues - -**Author** - Brian Skinn (bskinn@alum.mit.edu) - -**File Created** - 12 Jun 2022 - -**Copyright** - \(c) Brian Skinn 2016-2022 - -**Source Repository** - https://github.com/bskinn/sphobjinv - -**Documentation** - https://sphobjinv.readthedocs.io/en/latest - -**License** - The MIT License; see |license_txt|_ for full license terms - -**Members** - -""" - -from urllib import parse as urlparse - -from sphobjinv.error import SOIIsphxNoMatchingObjectError, SOIIsphxURINotASuffixError - - -def _strip_url_to_netloc_path(url, *, with_scheme=False): - """Reduce a URL to only netloc and path, optionally with scheme.""" - parts = urlparse.urlsplit(url) - trimmed = parts._replace( - query="", - fragment="", - ) - - if not with_scheme: - trimmed = trimmed._replace(scheme="") - - return urlparse.urlunsplit(trimmed) - - -def extract_objectsinv_url_base(objectsinv_url): - """Infer a base URL for the provided ``objects.inv`` inventory URL. - - If this function is a no-op, then the resulting base is NOT RELIABLE, - because the URL did not end with ``/objects.inv``. - - If this function *does* make a change, then the resulting base is - RELATIVELY RELIABLE, since the only change that should occur is - stripping of a ``/objects.inv`` suffix, which strongly implies but - does not guarantee that the URL came from a Sphinx docset in the - standard multi-page HTML layout. - - Parameters - ---------- - objectsinv_url - - |str| -- URL from which to attempt docset base inference - - Returns - ------- - trimmed - - |str| -- URL after attempt to trim a trailing ``/objects.inv`` - - """ - trimmed = _strip_url_to_netloc_path(objectsinv_url, with_scheme=True) - return f"{trimmed.rpartition('/objects.inv')[0]}/" - - -def _is_url_path_suffix(ref_url, suffix_candidate): - """Indicate whether the candidate path is a suffix of the reference URL.""" - # We want any fragments/queries/parameters to be stripped off of BOTH - # the ref_url and the suffix_candidate. - # The scheme of the ref_url doesn't matter since we're only inspecting - # the end of the URL. - return _strip_url_to_netloc_path(ref_url).endswith( - _strip_url_to_netloc_path(suffix_candidate) - ) - - -def _find_obj_with_matching_uri(ref_url, inv): - """Provide an object from the inventory whose URI is a suffix of the reference URL. - - Returns ``None`` if nothing found. - - """ - try: - return next( - o - for o in inv.objects - if o.uri # Must not be empty string - and not o.uri.startswith("#") # Must not only be a fragment - and _is_url_path_suffix(ref_url, o.uri) # Must be a suffix of the ref URL - ) - except StopIteration: - return None - - -def _extract_base_from_weburl_and_uri(web_url, uri): - """Extract the base URL from a reference web URL and the given URI. - - The base URL is returned **with** a trailing forward slash. - - Raises sphobjinv.error.SOIIsphxNotASuffixError if trimmed ``uri`` is - not actually a suffix of ``web_url``. - - """ - if not _is_url_path_suffix(web_url, uri): - raise SOIIsphxURINotASuffixError(web_url=web_url, uri=uri) - - trimmed = _strip_url_to_netloc_path(web_url, with_scheme=True) - - # TODO: Once the project drops Python < 3.9, can reimplement with .removesuffix() - return trimmed[: trimmed.find(_strip_url_to_netloc_path(uri))] - - -def _extract_base_from_weburl_and_inventory(web_url, inv): - """Extract a candidate base URL from a docset web URL and an Inventory instance.""" - obj = _find_obj_with_matching_uri(web_url, inv) - - if obj is None: - raise SOIIsphxNoMatchingObjectError(web_url=web_url, inv=inv) - - return _extract_base_from_weburl_and_uri(web_url, obj.uri) - - -def infer_mapping(web_url, objectsinv_url, inv): - """Infer a best-guess intersphinx_mapping entry for the given URLs and Inventory. - - Parameters - ---------- - web_url - - str -- URL of a valid page (optionally with fragment) from a live docset - - objectsinv_url - - str -- URL of the ``objects.inv`` file for the live docset - - inv - - |Inventory| -- Instantiated inventory for the live docset---MAY be generated - from the ``objects.inv`` at `objectsinv_url`, but CAN be generated from - any ``objects.inv`` corresponding to the **same version** of the live docset - - - Returns - ------- - mapping - - (str, str or None) -- Inferred ``intersphinx_mapping`` entry - - - """ - objectsinv_base = extract_objectsinv_url_base(objectsinv_url) - weburl_base = _extract_base_from_weburl_and_inventory(web_url, inv) - - return (weburl_base, None if objectsinv_base == weburl_base else objectsinv_url) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 21944d61..5a61175c 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -26,8 +26,8 @@ """ import sys +import urllib.parse as urlparse -import sphobjinv._intersphinx as soi_isphx from sphobjinv.cli.parser import PrsConst from sphobjinv.cli.ui import print_stderr, yesno_prompt @@ -184,7 +184,7 @@ def print_stderr_inferred_mapping(params): input_url = params[PrsConst.INFILE] inv_url = params[PrsConst.FOUND_URL] - reduced_inv_url = soi_isphx.extract_objectsinv_url_base(inv_url) + reduced_inv_url = extract_objectsinv_url_base(inv_url) if input_url == inv_url: # User provided an exact URL to an inventory @@ -232,3 +232,46 @@ def print_stderr_inferred_mapping(params): ), params, ) + + +def extract_objectsinv_url_base(objectsinv_url): + """Infer a base URL for the provided ``objects.inv`` inventory URL. + + If this function is a no-op, then the resulting base is NOT RELIABLE, + because the URL did not end with ``/objects.inv``. + + If this function *does* make a change, then the resulting base is + RELATIVELY RELIABLE, since the only change that should occur is + stripping of a ``/objects.inv`` suffix, which strongly implies but + does not guarantee that the URL came from a Sphinx docset in the + standard multi-page HTML layout. + + Parameters + ---------- + objectsinv_url + + |str| -- URL from which to attempt docset base inference + + Returns + ------- + trimmed + + |str| -- URL after attempt to trim a trailing ``/objects.inv`` + + """ + trimmed = _strip_url_to_netloc_path(objectsinv_url, with_scheme=True) + return f"{trimmed.rpartition('/objects.inv')[0]}/" + + +def _strip_url_to_netloc_path(url, *, with_scheme=False): + """Reduce a URL to only netloc and path, optionally with scheme.""" + parts = urlparse.urlsplit(url) + trimmed = parts._replace( + query="", + fragment="", + ) + + if not with_scheme: + trimmed = trimmed._replace(scheme="") + + return urlparse.urlunsplit(trimmed) diff --git a/tests/test_cli_nonlocal.py b/tests/test_cli_nonlocal.py index 01fa1f9a..680611ed 100644 --- a/tests/test_cli_nonlocal.py +++ b/tests/test_cli_nonlocal.py @@ -166,7 +166,7 @@ class TestSuggest: @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) def test_cli_suggest_from_url(self, misc_info, run_cmdline_test): - """Confirm name-only suggest works from URL.""" + """Confirm reST-only suggest output works from URL.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test( [ @@ -180,29 +180,38 @@ def test_cli_suggest_from_url(self, misc_info, run_cmdline_test): ) assert p_instance_of.search(out_.getvalue()) + @pytest.mark.parametrize( + "url", + [ + "http://sphobjinv.readthedocs.io/en/v2.0/modules/", + "http://sphobjinv.readthedocs.io/en/v2.0/modules/cmdline.html", + ( + "http://sphobjinv.readthedocs.io/en/v2.0/modules/" + "cmdline.html#sphobjinv.cmdline.do_convert" + ), + ], + ) @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) - def test_cli_suggest_from_dir_noanchor(self, run_cmdline_test): - """Confirm name-only suggest works from docpage URL.""" - url = "http://sphobjinv.readthedocs.io/en/v2.0/modules/" + def test_cli_suggest_from_docset_urls(self, url, run_cmdline_test, check): + """Confirm reST-only suggest output works from URLs within a docset.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", "-u", url, "inventory", "-at", "50"]) - assert p_inventory.search(out_.getvalue()) - @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) - def test_cli_suggest_from_page_noanchor(self, run_cmdline_test): - """Confirm name-only suggest works from docpage URL.""" - url = "http://sphobjinv.readthedocs.io/en/v2.0/modules/cmdline.html" - with stdio_mgr() as (in_, out_, err_): - run_cmdline_test(["suggest", "-u", url, "inventory", "-at", "50"]) - assert p_inventory.search(out_.getvalue()) + check.is_true(p_inventory.search(out_.getvalue())) + check.is_in("LIKELY", err_.getvalue()) + check.is_in( + "(http://sphobjinv.readthedocs.io/en/v2.0/, None)", err_.getvalue() + ) @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) - def test_cli_suggest_from_page_withanchor(self, run_cmdline_test): - """Confirm name-only suggest works from docpage URL.""" - url = ( - "http://sphobjinv.readthedocs.io/en/v2.0/modules/" - "cmdline.html#sphobjinv.cmdline.do_convert" - ) + def test_cli_suggest_from_objinv_url(self, run_cmdline_test, check): + """Confirm reST-only suggest works for direct objects.inv URL.""" + url = "http://sphobjinv.readthedocs.io/en/v2.0/objects.inv" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", "-u", url, "inventory", "-at", "50"]) - assert p_inventory.search(out_.getvalue()) + + check.is_true(p_inventory.search(out_.getvalue())) + check.is_in("PROBABLY", err_.getvalue()) + check.is_in( + "(http://sphobjinv.readthedocs.io/en/v2.0/, None)", err_.getvalue() + ) diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 98224425..925f07cf 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -27,8 +27,7 @@ import pytest -import sphobjinv as soi -import sphobjinv._intersphinx as soi_isphx +import sphobjinv.cli.suggest as soi_cli_suggest pytestmark = [pytest.mark.intersphinx, pytest.mark.local] @@ -58,7 +57,9 @@ ) def test_strip_netloc_path(uri, trimmed, with_scheme): """Confirm that object URI trimming is working.""" - assert trimmed == soi_isphx._strip_url_to_netloc_path(uri, with_scheme=with_scheme) + assert trimmed == soi_cli_suggest._strip_url_to_netloc_path( + uri, with_scheme=with_scheme + ) @pytest.mark.parametrize( @@ -72,66 +73,4 @@ def test_strip_netloc_path(uri, trimmed, with_scheme): ) def test_extract_objinv_url_base(url, trimmed): """Confirm that inventory URL trimming is working.""" - assert trimmed == soi_isphx.extract_objectsinv_url_base(url) - - -@pytest.mark.parametrize( - ("web_url", "inv_url", "project", "mapping"), - [ - ( - "https://flask.palletsprojects.com/en/1.1.x/api/#flask.Config", - "https://flask.palletsprojects.com/en/1.1.x/objects.inv", - "flask", - ("https://flask.palletsprojects.com/en/1.1.x/", None), - ), - ( - "https://docs.djangoproject.com/en/4.0/topics/cache/#memcached", - "https://docs.djangoproject.com/en/4.0/_objects/", - "django", - ( - "https://docs.djangoproject.com/en/4.0/", - "https://docs.djangoproject.com/en/4.0/_objects/", - ), - ), - ( - ( - "https://docs.scipy.org/doc/numpy-1.13.0/reference/" - "arrays.interface.html#python-side" - ), - "https://docs.scipy.org/doc/numpy-1.13.0/objects.inv", - "numpy", - ("https://docs.scipy.org/doc/numpy-1.13.0/", None), - ), - ], - ids=(lambda arg: arg if (isinstance(arg, str) and "/" not in arg) else ""), -) -def test_infer_mapping(web_url, inv_url, project, mapping, res_path): - """Confirm intersphinx mapping inference works for select test cases. - - These test(s) should continue to pass even if the various documentation sets - on the web are taken down. ``web_url`` and ``inv_url`` are chosen to be - valid and consistent with the versions of the |objects.inv| files stored - in the tests resource path `res_path`. - - """ - inv_path = res_path / f"objects_{project}.inv" - assert mapping == soi_isphx.infer_mapping(web_url, inv_url, soi.Inventory(inv_path)) - - -@pytest.mark.parametrize( - ("web_url", "project"), - [ - ( - "https://docs.djangoproject.com/en/4.0/topicXYZs/cache/#memcached", - "django", - ) - ], - ids=(lambda arg: arg if (isinstance(arg, str) and "/" not in arg) else ""), -) -def test_no_matching_object(web_url, project, res_path): - """Confirm that no matching Inventory object is found when there shouldn't be.""" - inv_path = res_path / f"objects_{project}.inv" - with pytest.raises(soi.SOIIsphxNoMatchingObjectError): - soi_isphx._extract_base_from_weburl_and_inventory( - web_url, soi.Inventory(inv_path) - ) + assert trimmed == soi_cli_suggest.extract_objectsinv_url_base(url) From 0e8f73c23d80aaafb769f7cc609f8147d7c5af30 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 22 Oct 2022 16:52:55 -0400 Subject: [PATCH 051/106] Fix objinv base finder and add Django test This is kind of a smelly way to do this, but it's concise and (I *think*) accurate to real-world situations. If it were in the formal API, I'd definitely want to do it differently, but for this purpose it's enough. --- src/sphobjinv/cli/suggest.py | 9 +++++++-- tests/test_cli_nonlocal.py | 12 +++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 5a61175c..a6285e8b 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -195,7 +195,7 @@ def print_stderr_inferred_mapping(params): # so we don't even have *that* point of reference to work with. print_stderr( ( - "Cannot infer intersphinx_mapping for this docset using\n" + "Cannot infer intersphinx_mapping for this docset using " "the provided input URL.\n" ), params, @@ -260,7 +260,12 @@ def extract_objectsinv_url_base(objectsinv_url): """ trimmed = _strip_url_to_netloc_path(objectsinv_url, with_scheme=True) - return f"{trimmed.rpartition('/objects.inv')[0]}/" + base = trimmed.rpartition("/objects.inv")[0] + + if base: + return f"{base}/" + else: + return objectsinv_url def _strip_url_to_netloc_path(url, *, with_scheme=False): diff --git a/tests/test_cli_nonlocal.py b/tests/test_cli_nonlocal.py index 680611ed..3861fff8 100644 --- a/tests/test_cli_nonlocal.py +++ b/tests/test_cli_nonlocal.py @@ -204,7 +204,7 @@ def test_cli_suggest_from_docset_urls(self, url, run_cmdline_test, check): ) @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) - def test_cli_suggest_from_objinv_url(self, run_cmdline_test, check): + def test_cli_suggest_from_typical_objinv_url(self, run_cmdline_test, check): """Confirm reST-only suggest works for direct objects.inv URL.""" url = "http://sphobjinv.readthedocs.io/en/v2.0/objects.inv" with stdio_mgr() as (in_, out_, err_): @@ -215,3 +215,13 @@ def test_cli_suggest_from_objinv_url(self, run_cmdline_test, check): check.is_in( "(http://sphobjinv.readthedocs.io/en/v2.0/, None)", err_.getvalue() ) + + @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) + def test_cli_suggest_from_django_objinv_url(self, run_cmdline_test, check): + """Confirm reST-only suggest works for direct objects.inv URL.""" + url = "https://docs.djangoproject.com/en/4.1/_objects/" + with stdio_mgr() as (in_, out_, err_): + run_cmdline_test(["suggest", "-u", url, "route", "-a"]) + + check.is_true(re.search("DATABASE_ROUTERS", out_.getvalue())) + check.is_in("Cannot infer intersphinx_mapping", err_.getvalue()) From 172db12621494134506845bfeb6be7fdff18160e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 22 Oct 2022 16:56:09 -0400 Subject: [PATCH 052/106] Fix README inv objects count --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 3d438d4c..4d153c4e 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,7 @@ For internal cross-references, locate ``objects.inv`` within ``build/html``:: $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 - 215 objects in inventory. + 217 objects in inventory. 11 results found at/above current threshold of 58. @@ -149,7 +149,7 @@ inventory creation/modification:: >>> import sphobjinv as soi >>> inv = soi.Inventory('doc/build/html/objects.inv') >>> print(inv) - + >>> inv.project 'sphobjinv' >>> inv.version From 9873da463d67f75ad8173d218bcb41563fba4d11 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 22 Oct 2022 23:37:45 -0400 Subject: [PATCH 053/106] Remove obsolete exceptions and add no cover Coverage solid. --- src/sphobjinv/__init__.py | 3 --- src/sphobjinv/cli/suggest.py | 2 +- src/sphobjinv/error.py | 38 ------------------------------------ 3 files changed, 1 insertion(+), 42 deletions(-) diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index 432076d8..1346e538 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -29,9 +29,6 @@ from sphobjinv.data import DataFields, DataObjBytes, DataObjStr from sphobjinv.enum import HeaderFields, SourceTypes from sphobjinv.error import ( - SOIIntersphinxError, - SOIIsphxNoMatchingObjectError, - SOIIsphxURINotASuffixError, SphobjinvError, VersionError, ) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index a6285e8b..dc949a5b 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -216,7 +216,7 @@ def print_stderr_inferred_mapping(params): if inv_url == reduced_inv_url: # This should never happen, because the only way we should be in # this outer else is if inv_url *DOES* end in /objects.inv - print_stderr( + print_stderr( # pragma: no cover ( "ERROR: Inconsistent internal state " "during intersphinx_mapping inference.\n" diff --git a/src/sphobjinv/error.py b/src/sphobjinv/error.py index 8fe48f18..939ac1ca 100644 --- a/src/sphobjinv/error.py +++ b/src/sphobjinv/error.py @@ -39,41 +39,3 @@ class VersionError(SphobjinvError): """ # TODO: Add SOI prefix to this class name as part of the exceptions refactor - - -class SOIIntersphinxError(SphobjinvError): - """Family of errors from the sphobjinv.intersphinx module.""" - - -class SOIIsphxURINotASuffixError(SOIIntersphinxError): - """Raised when a non-suffix URI is passed to the function matching.""" - - def __init__(self, *args, web_url, uri, **kwargs): - """Initialize the instance with base and suffix strings.""" - super().__init__(*args, **kwargs) - self.web_url = web_url - self.uri = uri - - def __str__(self): - """Provide human-readable exception message.""" - return f"'{self.uri}' is not a suffix of '{self.web_url}'" - - -class SOIIsphxNoMatchingObjectError(SOIIntersphinxError): - """Raised when an Inventory does not have an object matching a reference URL. - - "Matching" here means that the object's URI is a suffix of the reference URL, - after both reference URL and suffix have their query and fragment components - removed. - - """ - - def __init__(self, *args, web_url, inv, **kwargs): - """Initialize the instance with reference URL and Inventory.""" - super().__init__(*args, **kwargs) - self.web_url = web_url - self.inv = inv - - def __str__(self): - """Provide human-readable exception message.""" - return f"'{self.inv}' does not have an object matching '{self.web_url}'" From a84118648b2e89f213264f4fde3ff5969218156c Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 22 Oct 2022 23:47:59 -0400 Subject: [PATCH 054/106] Tweak CLI docs wording --- doc/source/cli/convert.rst | 6 +++--- doc/source/cli/index.rst | 18 +++++++++++------- doc/source/cli/suggest.rst | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/doc/source/cli/convert.rst b/doc/source/cli/convert.rst index caf15b77..5b91342d 100644 --- a/doc/source/cli/convert.rst +++ b/doc/source/cli/convert.rst @@ -1,11 +1,11 @@ .. Description of convert commandline usage -Command-Line Usage: "convert" Mode -================================== +Command-Line Usage: "convert" Subcommand +======================================== .. program:: sphobjinv convert -The |cour|\ convert\ |/cour| subparser is used for all conversions of +The |cour|\ convert\ |/cour| subcommand is used for all conversions of "version 2" Sphinx inventory files among plaintext, zlib-compressed, and (unique to |soi|) JSON formats. The |soi| CLI can read and write inventory data from local files diff --git a/doc/source/cli/index.rst b/doc/source/cli/index.rst index ae6a4a22..1974dbdc 100644 --- a/doc/source/cli/index.rst +++ b/doc/source/cli/index.rst @@ -3,17 +3,23 @@ Command-Line Usage ================== -The CLI for |soi| is implemented using two subparsers, one each for the -:doc:`convert ` and :doc:`suggest ` sub-functions. -More information about the implementation of these features can be -found :doc:`here ` and in the documentation for the +The CLI for |soi| is implemented using two subcommands: + + - A :doc:`convert ` subcommand, which handles conversion of + inventories between supported formats (currently zlib-compressed, + plaintext, and JSON). + - A :doc:`suggest ` subcommand, which provides suggestions for + objects in an inventory matching a desired search term. + +More information about the underlying implementation of these subcommands can +be found :doc:`here ` and in the documentation for the :class:`~sphobjinv.inventory.Inventory` object, in particular the :meth:`~sphobjinv.inventory.Inventory.data_file` and :meth:`~sphobjinv.inventory.Inventory.suggest` methods. Some notes on these CLI docs: - * CLI examples are executed in a sandboxed directory pre-loaded with + * CLI docs examples are executed in a sandboxed directory pre-loaded with |cour|\ objects_attrs.inv\ |/cour| (from, e.g., `here `__). @@ -54,5 +60,3 @@ The options for the parent |soi| command are: "convert" Mode "suggest" Mode - - diff --git a/doc/source/cli/suggest.rst b/doc/source/cli/suggest.rst index 44ad03e4..26cfc967 100644 --- a/doc/source/cli/suggest.rst +++ b/doc/source/cli/suggest.rst @@ -1,7 +1,7 @@ .. Description of suggest commandline usage -Command-Line Usage: "suggest" Mode -================================== +Command-Line Usage: "suggest" Subcommand +======================================== .. program:: sphobjinv suggest From 6cf10009abbe5f4af309b2f501b37e4b484e0f55 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 23 Oct 2022 10:24:25 -0400 Subject: [PATCH 055/106] Fix object count in README --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 4d153c4e..86794f03 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,7 @@ For internal cross-references, locate ``objects.inv`` within ``build/html``:: $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 - 217 objects in inventory. + 214 objects in inventory. 11 results found at/above current threshold of 58. @@ -149,7 +149,7 @@ inventory creation/modification:: >>> import sphobjinv as soi >>> inv = soi.Inventory('doc/build/html/objects.inv') >>> print(inv) - + >>> inv.project 'sphobjinv' >>> inv.version From 40402d340bc18e5b72e4f33612c142ebc4a4fd37 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 23 Oct 2022 19:51:12 -0400 Subject: [PATCH 056/106] Fix --flake8_ext test glitch --- tests/test_flake8_ext.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_flake8_ext.py b/tests/test_flake8_ext.py index 00bae72f..a13fa20d 100644 --- a/tests/test_flake8_ext.py +++ b/tests/test_flake8_ext.py @@ -58,7 +58,7 @@ def test_flake8_version_output(check): # This is fragile if anything ends up not having a prefix that needs # stripping - plugins = [p.partition("-")[-1] for p in plugins] + plugins = [p.partition("flake8-")[-1] for p in plugins] flake8_ver_output = sp.check_output( # noqa: S607,S603 ["flake8", "--version"], universal_newlines=True @@ -66,4 +66,4 @@ def test_flake8_version_output(check): for p in plugins: with check.check(msg=p): - assert p in flake8_ver_output.replace("_", "-") + assert p in flake8_ver_output.replace("_", "-").replace("\n", "") From 54640563f888aaa23c5f2bb5f872d78f4f04594b Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 23 Oct 2022 23:29:03 -0400 Subject: [PATCH 057/106] Un-break README shell command test output Had been masking it, yeesh. --- tests/test_readme.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_readme.py b/tests/test_readme.py index 9070cd3a..388060eb 100644 --- a/tests/test_readme.py +++ b/tests/test_readme.py @@ -69,7 +69,7 @@ def test_readme_shell_cmds(ensure_doc_scratch, check): dt_flags = dt.ELLIPSIS | dt.NORMALIZE_WHITESPACE - for i, mch in enumerate(p_shell.finditer(text)): + for mch in p_shell.finditer(text): cmd = mch.group("cmd") out = mch.group("out") @@ -81,5 +81,5 @@ def test_readme_shell_cmds(ensure_doc_scratch, check): msg = "\n\nExpected:\n" + out + "\n\nGot:\n" + result - with check.check(msg=f"match_{i}"): + with check.check(): assert chk.check_output(out, result, dt_flags), msg From 5d3da4beb030087c4dc51962ef2ea344bbcf6e32 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Mon, 24 Oct 2022 10:14:14 -0400 Subject: [PATCH 058/106] Add sleeps to see if fixes Win shell tests Don't really want to leave them in there, but if it's just a race condition on when things make it to the streams... :-/ --- src/sphobjinv/cli/suggest.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index dc949a5b..398c46f0 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -26,6 +26,7 @@ """ import sys +import time import urllib.parse as urlparse from sphobjinv.cli.parser import PrsConst @@ -73,14 +74,18 @@ def do_suggest(inv, params): ) print_stderr(f"{inv.count} objects in inventory.\n", params) + time.sleep(0.2) print_stderr_result_count(params, results) + time.sleep(0.2) print_stderr_inferred_mapping(params) + time.sleep(0.2) # The query here for printing the full list only occurs in some # circumstances; see the function docstring. confirm_print_if_long_list(params, results) + time.sleep(0.2) print_results_table(with_index, with_score, results) From d9cde34a17147da7f066329846266068f66f278e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Mon, 24 Oct 2022 10:23:36 -0400 Subject: [PATCH 059/106] Revert "Add sleeps to see if fixes Win shell tests" This reverts commit 5d3da4beb030087c4dc51962ef2ea344bbcf6e32. Sleeps do *not* help; Windows is just reassembling the stdout/stderr out of order --- src/sphobjinv/cli/suggest.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 398c46f0..dc949a5b 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -26,7 +26,6 @@ """ import sys -import time import urllib.parse as urlparse from sphobjinv.cli.parser import PrsConst @@ -74,18 +73,14 @@ def do_suggest(inv, params): ) print_stderr(f"{inv.count} objects in inventory.\n", params) - time.sleep(0.2) print_stderr_result_count(params, results) - time.sleep(0.2) print_stderr_inferred_mapping(params) - time.sleep(0.2) # The query here for printing the full list only occurs in some # circumstances; see the function docstring. confirm_print_if_long_list(params, results) - time.sleep(0.2) print_results_table(with_index, with_score, results) From 2d24cef4bff51b74d09ed723b8212e540e0efd23 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Mon, 24 Oct 2022 10:46:27 -0400 Subject: [PATCH 060/106] Add Win < Python 3.9 skip Just not worrying about how subprocess handles stdout/stderr ordering for these. --- tests/test_readme.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_readme.py b/tests/test_readme.py index 388060eb..a512738e 100644 --- a/tests/test_readme.py +++ b/tests/test_readme.py @@ -30,6 +30,7 @@ import re import shlex import subprocess as sp # noqa: S404 +import sys from pathlib import Path @@ -61,8 +62,11 @@ "pypy" in platform.python_implementation().lower(), reason="Inconsistent suggest results on PyPy", ) -def test_readme_shell_cmds(ensure_doc_scratch, check): +def test_readme_shell_cmds(ensure_doc_scratch, is_win, check): """Perform testing on README shell command examples.""" + if is_win and sys.version_info < (3, 9): # pragma: no cover + pytest.skip("Windows mishandles stdout/stderr for Python < 3.9") + text = Path("README.rst").read_text() chk = dt.OutputChecker() From 0213bbb8f8075b2dc36a33380a66932c9d541f63 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Wed, 26 Oct 2022 00:02:06 -0400 Subject: [PATCH 061/106] Clean up the error imports The new errors that had been added for _intersphinx.py had left the sphobjinv.error import line split. No need, when it all fits on one line. --- src/sphobjinv/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index 1346e538..bfdf67be 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -28,10 +28,7 @@ from sphobjinv.data import DataFields, DataObjBytes, DataObjStr from sphobjinv.enum import HeaderFields, SourceTypes -from sphobjinv.error import ( - SphobjinvError, - VersionError, -) +from sphobjinv.error import SphobjinvError, VersionError from sphobjinv.fileops import readbytes, readjson, urlwalk, writebytes, writejson from sphobjinv.inventory import Inventory from sphobjinv.re import p_data, pb_comments, pb_data, pb_project, pb_version From 5acd50b68204eab5fe27d77b63441d97b162239a Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Wed, 26 Oct 2022 00:03:45 -0400 Subject: [PATCH 062/106] Update CHANGELOG Numerous bits and pieces. Closes #149. --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9810c55..fb36ac38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project strives to adhere to #### Added + * The CLI now prints an inferred `intersphinx_mapping` entry for a remote + docset as part of the 'suggest' mode output, where such inference is + possible. The output from this mapping inference was added to the relevant + tests, and a couple of unit tests on some basic pieces of functionality were + written. ([#149](https://github.com/bskinn/sphobjinv/issues/149)) + * The CLI now provides considerably more information about what is happening with the URLs it checks when trying to retrieve a remote inventory. ([#99](https://github.com/bskinn/sphobjinv/issues/99), plus more) @@ -21,8 +27,30 @@ and this project strives to adhere to now results in a clean error-exit, instead of an exception. ([#239](https://github.com/bskinn/sphobjinv/issues/239)) +#### Documentation + + * Add new 'CLI implementation' pages for the new modules, downstream of the + refactoring of the CLI 'convert' and 'suggest' code. + + * Revise the intro paragraph of the 'CLI usage' page to more clearly emphasize + the two CLI subcommands and the links to their respective docs pages. + #### Internal + * Refactor CLI code to place the 'convert' and 'suggest' implementations in + their own modules. + + * Refactor CLI 'suggest' code to the main `do_suggest()` function and a + handful of sub-functions. + + * Rename the `log_print()` CLI helper function to the more-descriptive + `print_stderr()`. + + * Bump development Sphinx version to v5.3. + + * Bump flake8 version to >=5, due to the absorption of flake8-colors + colorization functionality. The flake8/tox config was updated accordingly. + * Bump pre-commit black hook to v22.3.0. * Remove PyPy and Python 3.6 from Azure Pipelines test matrix. From 605752780e44300b79636beb583be0c4cb1c0e2e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 27 Oct 2022 21:32:54 -0400 Subject: [PATCH 063/106] Add pipx references --- README.rst | 5 +++-- doc/source/conf.py | 4 ++++ doc/source/index.rst | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 86794f03..717d6aba 100644 --- a/README.rst +++ b/README.rst @@ -49,8 +49,9 @@ you mean, but it's pretty hit-or-miss. The best approach is to provide Sphinx with a completely specified cross-reference, and that's where ``sphobjinv`` comes in. -After a ``pip install sphobjinv``, find the documentation set you want -to cross-reference into, and pass it to ``sphobjinv suggest``. +After a ``pip install sphobjinv`` (or ``pipx install sphobjinv``), find the +documentation set you want to cross-reference into, and pass it to +``sphobjinv suggest``. For internal cross-references, locate ``objects.inv`` within ``build/html``:: diff --git a/doc/source/conf.py b/doc/source/conf.py index 254089f3..ac7206bb 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -126,6 +126,10 @@ .. _fuzzywuzzy: https://github.com/seatgeek/fuzzywuzzy +.. |pipx| replace:: ``pipx`` + +.. _pipx: https://pypa.github.io/pipx/ + .. |python-Levenshtein| replace:: ``python-Levenshtein`` .. _python-Levenshtein: https://pypi.org/project/python-Levenshtein diff --git a/doc/source/index.rst b/doc/source/index.rst index cea37fcf..488bd638 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -41,6 +41,10 @@ Install |soi| via |cour|\ pip\ |/cour|:: $ pip install sphobjinv +Or, if you only plan to use the |soi| CLI, another option is |pipx|_:: + + $ pipx install sphobjinv + Alternatively, |soi| is packaged with `multiple POSIX distributions `__ and package managers, including: From 399ccf522b46553e4e3b5c97e5d3d005632daccd Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 28 Oct 2022 21:06:59 -0400 Subject: [PATCH 064/106] Tweak Sphinx theme styles - Lighter blue in the logo box - White version text - Stronger border around the search box - Brigher white l1 sidebar TOC text --- doc/source/_static/css/custom.css | 16 ++++++++++++++++ doc/source/_static/soi-logo_duo_border.png | Bin 28803 -> 31213 bytes doc/source/_static/soi-logo_duo_border.xcf | Bin 28060 -> 28020 bytes doc/source/conf.py | 5 +++++ 4 files changed, 21 insertions(+) create mode 100644 doc/source/_static/css/custom.css diff --git a/doc/source/_static/css/custom.css b/doc/source/_static/css/custom.css new file mode 100644 index 00000000..a2471dd3 --- /dev/null +++ b/doc/source/_static/css/custom.css @@ -0,0 +1,16 @@ +div.wy-side-nav-search { + background-color: #7ebbff; +} + +div.version { + color: #ffffff !important; + font-weight: bolder !important; +} + +li.toctree-l1:not(.current) a { + color: #f8f8f8 !important; +} + +form.wy-form input { + border: 3px solid #6eabef !important; +} diff --git a/doc/source/_static/soi-logo_duo_border.png b/doc/source/_static/soi-logo_duo_border.png index a60917b9693c60391f1cae71a101bae53baa073b..cda86fa6b907dd1ad620cf8bea6273bf8543b5c7 100644 GIT binary patch literal 31213 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 D2l8@h literal 28803 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 GLyGBP9)Nkehn#Q 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 Ocqb($FIpvR=>I=-_W1Gu diff --git a/doc/source/_static/soi-logo_duo_border.xcf b/doc/source/_static/soi-logo_duo_border.xcf index 08e351896262841417713e7e1b3fec44d853352a..a1e37544ceb45b29667f3836cd765bc29cb66588 100644 GIT binary patch delta 1050 zcma))KZw(C6vy*RI$bRW#d@|Kigzb>V(kS7hbx6UK@_A2I*168_L?+lb3NLCI{k`* zgGEuYouY%AiXs^VC(%g|J2(h;f`gklc^!rNP2Q_;)j`7dee(X~$9un*2U}veDekTq z`xHedHny=cmcB|dV&&Mcq z?5deJ=!w!-yX$7nS+n!TBD`yVyx@^KlZ+y5%j(wse6XeF?p@4@+b^%27r}PiLbLj$QxWwbK@Kl!Et^`Qau zcYenK|EL$eiWI#*G=N6Xgr9+*K|V8(;k1($Vs}t&(WdV}{6DmO%6XTV4PtD^ zwQyP=DBk+Q{K5Q1^mZ|G%p=SaT8du1GZdIy7VdiT?o-%R3cE^SSE>Kl)nvVf-DudA WhFxjcRdzC; zK^pdGz2xelhZQ7v33}6;C$R^?qaM5zFFnLJ``${s8S=kx-v8btlQ(cGC{+%TrKiWlsd%x(IBqRrfYTQ+r&0`n}qz z#ievrmnJq1a{6y(Z)L^It4?ezYwFzNUe|U+$E!B7Zv*p5-t2!neXxArb$hMw|L?;I zbm|W~BCLvzWn z;t%A^ZDj2cvhe_U<12D)4(Wa*lJEXZc8X^l23iFT`EqZ{j{v=}wf;U`&;n1&TmJ(0C#*jVx6fMW7*QvYtPm@8^-F zcocz#pz$1pLx$oN$ScrL876=HlU%K2cLOG%mmnIDbg%>)JlNch?SJ5vcK?7A*>9ZU#AU`%@APE|P^s^kU=kt7jA!4c!Nzec^2IX=Cas%qd JK*ei;`46=U;J5$) diff --git a/doc/source/conf.py b/doc/source/conf.py index ac7206bb..64664b40 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -325,3 +325,8 @@ def file_head(fn, *, head=None): # Location of the favicon and logo images html_favicon = "_static/soi-logo.png" html_logo = "_static/soi-logo_duo_border.png" + +# Adding custom CSS +html_css_files = [ + "css/custom.css", +] From 59327515bf54d0db568d4ac5cfb224bcf57251c6 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 28 Oct 2022 23:38:37 -0400 Subject: [PATCH 065/106] Add --paginate flag to suggest CLI --- src/sphobjinv/cli/parser.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sphobjinv/cli/parser.py b/src/sphobjinv/cli/parser.py index e959b47d..ea60fe9e 100644 --- a/src/sphobjinv/cli/parser.py +++ b/src/sphobjinv/cli/parser.py @@ -147,6 +147,10 @@ class PrsConst: #: number returned, without asking for confirmation ALL = "all" + #: Optional argument name for use with the :data:`SUGGEST` subparser, + #: indicating to paginate the suggest subcommand results + PAGINATE = "paginate" + # ### Helper strings #: Help text for the :data:`CONVERT` subparser HELP_CO_PARSER = ( @@ -331,6 +335,12 @@ def getparser(): "without prompting for confirmation.", action="store_true", ) + spr_suggest.add_argument( + "-" + PrsConst.PAGINATE[0], + "--" + PrsConst.PAGINATE, + help="Paginate long search results", + action="store_true", + ) spr_suggest.add_argument( "-" + PrsConst.INDEX[0], "--" + PrsConst.INDEX, From fcda6e2c4c1c692fb1f64bbfa56b621e296d60cb Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 28 Oct 2022 23:39:59 -0400 Subject: [PATCH 066/106] Start conversion of suggest output to generators First step in implementing pagination of suggest output [skip ci] --- src/sphobjinv/cli/suggest.py | 61 +++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index dc949a5b..9effb721 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -82,7 +82,7 @@ def do_suggest(inv, params): # circumstances; see the function docstring. confirm_print_if_long_list(params, results) - print_results_table(with_index, with_score, results) + print_results_table(with_index, with_score, results, params) def print_stderr_result_count(params, results): @@ -131,7 +131,7 @@ def confirm_print_if_long_list(params, results): print_stderr("", params) -def print_results_table(with_index, with_score, results): +def print_results_table(with_index, with_score, results, params): """Prepare and print the table of suggest search results.""" # Field widths in output score_width = 7 @@ -154,23 +154,54 @@ def print_results_table(with_index, with_score, results): # TODO: Consider replacing this with a *real* table formatting tool if with_index: if with_score: - fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}} {{2: ^{index_width}}}" - print(fmt.format(" Name", "Score", "Index")) - print(fmt.format("-" * rst_width, "-" * score_width, "-" * index_width)) - print("\n".join(fmt.format(*res) for res in results)) + ... else: - fmt = f"{{0: <{rst_width}}} {{1: ^{index_width}}}" - print(fmt.format(" Name", "Index")) - print(fmt.format("-" * rst_width, "-" * index_width)) - print("\n".join(fmt.format(*res) for res in results)) + ... else: if with_score: - fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}}" - print(fmt.format(" Name", "Score")) - print(fmt.format("-" * rst_width, "-" * score_width)) - print("\n".join(fmt.format(*res) for res in results)) + ... else: - print("\n".join(str(res) for res in results)) + gen = generate_names_only_lines + + if params[PrsConst.PAGINATE]: + ... + else: + print("\n".join(gen(results))) + + # if with_index: + # if with_score: + # fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}} {{2: ^{index_width}}}" + # print(fmt.format(" Name", "Score", "Index")) + # print(fmt.format("-" * rst_width, "-" * score_width, "-" * index_width)) + # print("\n".join(fmt.format(*res) for res in results)) + # else: + # fmt = f"{{0: <{rst_width}}} {{1: ^{index_width}}}" + # print(fmt.format(" Name", "Index")) + # print(fmt.format("-" * rst_width, "-" * index_width)) + # print("\n".join(fmt.format(*res) for res in results)) + # else: + # if with_score: + # fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}}" + # print(fmt.format(" Name", "Score")) + # print(fmt.format("-" * rst_width, "-" * score_width)) + # print("\n".join(fmt.format(*res) for res in results)) + # else: + # print("\n".join(str(res) for res in results)) + + +# def generate_results_table_lines(results, with_index, with_score, index_width=7, score_width=7): +# """Yield the individual lines of the suggest results output.""" +# # TODO: This could be swapped to use pattern matching once < 3.9 is out of support +# flags = (with_index, with_score) + +# if flags == (True, True): + +# elif flags == () + + +def generate_names_only_lines(results): + """Yield lines to print containing just the object search results.""" + yield from (str(res) for res in results) def print_stderr_inferred_mapping(params): From 8d149e7cce56d7fe75fe2d1ad6246f0e751a13cd Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 29 Oct 2022 19:25:20 -0400 Subject: [PATCH 067/106] Implement generator-based results table For the name-only case, at least. Now have to implement the generators for the other three cases. [skip ci] --- src/sphobjinv/cli/suggest.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 9effb721..90a154c7 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -25,6 +25,8 @@ """ +import itertools as itt +import shutil import sys import urllib.parse as urlparse @@ -159,14 +161,32 @@ def print_results_table(with_index, with_score, results, params): ... else: if with_score: - ... + pass else: - gen = generate_names_only_lines + gen = generate_names_only_lines(results) - if params[PrsConst.PAGINATE]: - ... + if not params[PrsConst.PAGINATE]: + print("\n".join(gen)) else: - print("\n".join(gen(results))) + # To make sure the initial output is not scrolled off the screen + # when --all is specified. + if params[PrsConst.ALL]: + input("Press Enter to continue...") + + while True: + # Adjust the number of lines per page if the user changes their + # terminal window size mid-execution + n_lines = shutil.get_terminal_size().lines - 2 + out_text = "\n".join(itt.islice(gen, n_lines)) + + if out_text: + print(out_text) + # Don't paginate after the last, partial screenful of output + if out_text.count("\n") == n_lines - 1: + input("Press Enter to continue...") + else: + # join() above will supply an empty string once gen is exhausted + break # if with_index: # if with_score: From f65d53cbd017657d0ba9ffcab0a0b4a2a4b150a8 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 30 Oct 2022 00:07:16 -0400 Subject: [PATCH 068/106] Add generator for with_score table [skip ci] --- src/sphobjinv/cli/suggest.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 90a154c7..7866180d 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -161,7 +161,7 @@ def print_results_table(with_index, with_score, results, params): ... else: if with_score: - pass + gen = generate_score_lines(results, score_width, rst_width) else: gen = generate_names_only_lines(results) @@ -209,14 +209,12 @@ def print_results_table(with_index, with_score, results, params): # print("\n".join(str(res) for res in results)) -# def generate_results_table_lines(results, with_index, with_score, index_width=7, score_width=7): -# """Yield the individual lines of the suggest results output.""" -# # TODO: This could be swapped to use pattern matching once < 3.9 is out of support -# flags = (with_index, with_score) - -# if flags == (True, True): - -# elif flags == () +def generate_score_lines(results, score_width, rst_width): + """Yield lines to print the table with scores.""" + fmt = f"{{name: <{rst_width}}} {{score: ^{score_width}}}" + yield fmt.format(name=" Name", score="Score") + yield fmt.format(name=("-" * rst_width), score=("-" * score_width)) + yield from (fmt.format(name=res[0], score=res[1]) for res in results) def generate_names_only_lines(results): From cc0be5ba530f09e75b449084b3632e4c4508bfa4 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Mon, 31 Oct 2022 23:36:45 -0400 Subject: [PATCH 069/106] Complete generators implementation Tests pass! Pagination works by manual testing! Now to add an automated test or so, and call it a day. --- src/sphobjinv/cli/suggest.py | 44 +++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 7866180d..1be2c3db 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -156,9 +156,11 @@ def print_results_table(with_index, with_score, results, params): # TODO: Consider replacing this with a *real* table formatting tool if with_index: if with_score: - ... + gen = generate_score_index_lines( + results, score_width, index_width, rst_width + ) else: - ... + gen = generate_index_lines(results, index_width, rst_width) else: if with_score: gen = generate_score_lines(results, score_width, rst_width) @@ -188,25 +190,25 @@ def print_results_table(with_index, with_score, results, params): # join() above will supply an empty string once gen is exhausted break - # if with_index: - # if with_score: - # fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}} {{2: ^{index_width}}}" - # print(fmt.format(" Name", "Score", "Index")) - # print(fmt.format("-" * rst_width, "-" * score_width, "-" * index_width)) - # print("\n".join(fmt.format(*res) for res in results)) - # else: - # fmt = f"{{0: <{rst_width}}} {{1: ^{index_width}}}" - # print(fmt.format(" Name", "Index")) - # print(fmt.format("-" * rst_width, "-" * index_width)) - # print("\n".join(fmt.format(*res) for res in results)) - # else: - # if with_score: - # fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}}" - # print(fmt.format(" Name", "Score")) - # print(fmt.format("-" * rst_width, "-" * score_width)) - # print("\n".join(fmt.format(*res) for res in results)) - # else: - # print("\n".join(str(res) for res in results)) + +def generate_score_index_lines(results, score_width, index_width, rst_width): + """Yield lines to print the table with scores & indices.""" + fmt = ( + f"{{name: <{rst_width}}} {{score: ^{score_width}}} {{index: ^{index_width}}}" + ) + yield fmt.format(name=" Name", score="Score", index="Index") + yield fmt.format( + name=("-" * rst_width), score=("-" * score_width), index=("-" * index_width) + ) + yield from (fmt.format(name=res[0], score=res[1], index=res[2]) for res in results) + + +def generate_index_lines(results, index_width, rst_width): + """Yield lines to print the table with indices.""" + fmt = f"{{name: <{rst_width}}} {{index: ^{index_width}}}" + yield fmt.format(name=" Name", index="Index") + yield fmt.format(name=("-" * rst_width), index=("-" * index_width)) + yield from (fmt.format(name=res[0], index=res[1]) for res in results) def generate_score_lines(results, score_width, rst_width): From dfca0e811006c5dc9781812a401dad25fc64f2ca Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 1 Nov 2022 12:42:31 -0400 Subject: [PATCH 070/106] Fix README inventory object counts --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 717d6aba..929dd06d 100644 --- a/README.rst +++ b/README.rst @@ -57,7 +57,7 @@ For internal cross-references, locate ``objects.inv`` within ``build/html``:: $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 - 214 objects in inventory. + 219 objects in inventory. 11 results found at/above current threshold of 58. @@ -150,7 +150,7 @@ inventory creation/modification:: >>> import sphobjinv as soi >>> inv = soi.Inventory('doc/build/html/objects.inv') >>> print(inv) - + >>> inv.project 'sphobjinv' >>> inv.version From bfa877de46c97950127058e85ed4fc872c404401 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 1 Nov 2022 13:16:39 -0400 Subject: [PATCH 071/106] Add basic pagination CLI test Also, fix a few nearby test docstrings. --- tests/test_cli.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 8f3212d7..ee47d1f2 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -358,14 +358,14 @@ def test_cli_suggest_withindex(self, run_cmdline_test, res_cmp): @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_withscore(self, run_cmdline_test, res_cmp): - """Confirm with_index suggest works.""" + """Confirm with_score suggest works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-st", "50"]) re.search("^.*instance_of\\S*\\s+\\d+\\s*$", out_.getvalue(), re.M) @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_withscoreandindex(self, run_cmdline_test, res_cmp): - """Confirm with_index suggest works.""" + """Confirm with_index + with_score suggest works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-sit", "50"]) re.search("^.*instance_of\\S*\\s+\\d+\\s+23\\s*$", out_.getvalue(), re.M) @@ -376,11 +376,12 @@ def test_cli_suggest_withscoreandindex(self, run_cmdline_test, res_cmp): ) # Extra line for input() query in the "y\n" case @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_long_list(self, inp, flags, nlines, run_cmdline_test, res_cmp): - """Confirm with_index suggest works.""" + """Confirm suggest with a long list of results works.""" with stdio_mgr(inp) as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", flags, "1"]) assert nlines == out_.getvalue().count("\n") + @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_many_results_stdin(self, res_cmp, run_cmdline_test): """Confirm suggest from stdin doesn't choke on a long list.""" data = json.dumps(Inventory(res_cmp).json_dict()) @@ -388,6 +389,13 @@ def test_cli_suggest_many_results_stdin(self, res_cmp, run_cmdline_test): with stdio_mgr(data) as (in_, out_, err_): run_cmdline_test(["suggest", "-", "py", "-t", "1"]) + @pytest.mark.timeout(CLI_TEST_TIMEOUT) + def test_cli_suggest_paginated(self, res_cmp, run_cmdline_test): + """Confirm pagination works as expected for a controlled example.""" + with stdio_mgr("\n\n") as (in_, out_, err_): + run_cmdline_test(["suggest", res_cmp, "function", "-sapt30"]) + assert 2 == out_.getvalue().count("Press Enter to continue") + class TestFail: """Tests for expected-fail behaviors.""" From ab4832bb7baf3c3fc22d2ab9e7c01176fb04e128 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Tue, 1 Nov 2022 22:59:43 -0400 Subject: [PATCH 072/106] Add CHANGELOG and fix some docs Closes #70. --- CHANGELOG.md | 5 +++++ src/sphobjinv/cli/core.py | 2 +- src/sphobjinv/cli/parser.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb36ac38..456aed9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ and this project strives to adhere to with the URLs it checks when trying to retrieve a remote inventory. ([#99](https://github.com/bskinn/sphobjinv/issues/99), plus more) + * A new CLI option, `-p`/`--paginate`, enables paging of the results from the + `suggest` feature. ([#70](https://github.com/bskinn/sphobjinv/issues/70)) + #### Fixed * CLI corner case where options are passed but no subparser is specified @@ -35,6 +38,8 @@ and this project strives to adhere to * Revise the intro paragraph of the 'CLI usage' page to more clearly emphasize the two CLI subcommands and the links to their respective docs pages. + * Fixed a mistake in the CLI help info for the `--url` argument to `convert`. + #### Internal * Refactor CLI code to place the 'convert' and 'suggest' implementations in diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index 08316fb6..b6a914f0 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -55,7 +55,7 @@ def main(): # Parse commandline arguments, discarding any unknown ones # I forget why I set it up to discard these, it might be - # more confusing than it's worth.... + # more confusing than it's worth to swallow them this way.... prs = getparser() ns, _ = prs.parse_known_args() params = vars(ns) diff --git a/src/sphobjinv/cli/parser.py b/src/sphobjinv/cli/parser.py index ea60fe9e..1e8798b3 100644 --- a/src/sphobjinv/cli/parser.py +++ b/src/sphobjinv/cli/parser.py @@ -313,7 +313,7 @@ def getparser(): "--" + PrsConst.URL, help=( "Treat 'infile' as a URL for download. " - f"Cannot be used with --{PrsConst.URL}." + "Cannot be used with an infile of '-'." ), action="store_true", ) From 5954aaf55b81cf60678b9bf20191adc44aa8320f Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 3 Nov 2022 14:21:17 -0400 Subject: [PATCH 073/106] Add/swap objects.inv files in tests/resource --- tests/resource/objects_attrs.inv | Bin 834 -> 1434 bytes tests/resource/objects_attrs.json | 2 +- tests/resource/objects_attrs.txt | 135 ++- tests/resource/objects_attrs_17_2_0.inv | Bin 0 -> 834 bytes tests/resource/objects_sphinx.inv | Bin 9674 -> 14192 bytes tests/resource/objects_sphinx.txt | 1475 +++++++++++++++++++++++ tests/resource/objects_sphinx_1_6_6.inv | Bin 0 -> 9674 bytes 7 files changed, 1580 insertions(+), 32 deletions(-) create mode 100644 tests/resource/objects_attrs_17_2_0.inv create mode 100644 tests/resource/objects_sphinx.txt create mode 100644 tests/resource/objects_sphinx_1_6_6.inv diff --git a/tests/resource/objects_attrs.inv b/tests/resource/objects_attrs.inv index b648b4b88261e619e88b7f64e50596566d28270a..85189bdf1858248a4f6b3eead8acdc496c072967 100644 GIT binary patch delta 1340 zcmV-C1;hHn2AT_yIRr8?E-{fkI)9y6!E)m$5WVviR86i*?Ob!&@@6IzSM4OJO?Glr z5vgragFq#a6VGYCWI|O~Q<+X|=y8Ro)1ozfmr8__!`i zDLy$_azzuu5O)0oYR#2g%Z;*>OfaqKXUZz>@I5ds*-yA$;U|A<3>?780Do%QtN*m4PHcT(83-;L!`?)wY7M5{nuo{q@#$>X$*l(Nmqsl)eLQP&7-xXvnAWCtb=UDxk3Iz`jF=wiG(NOF*cS*gUnhBzGw^ z<(pJ02~k|t#x)aBq<@N6aaN2<-;@e45?1tdV1J}9s*X#FLQ39}j^$z&rr~1ZnQFA8 zV7b%;XgE_wme>nrVu>DD1t!%5C3hXzk?WXlT*r3eI<^bfAssljyZF*eUE*BCMs@0k z-qbLgSBDOLJY0ZOwm8Tk zs#@)M9+F`OBpn)V6{p(dH@V7&F9W)ITGPK^12tf5SXAosMT^E`2Qhw0R6OYr&+d22 z8nn*y!~y6>|9?q*`#GY)2P?7F)ZGGZT`sj3-Y6Ui0qrt1eX&WIWCfF35NbPIWG{3} zz3ql1Q)R_!u5p`&@LuZi{g@njz_FWLa&zRO-H@!&MwQ8tnVxlI$Z}f(|HbT@NV^?v zZ31Txm6n#c6-sMX?;Xub6N^ncY(jGE1)-+y;jm0@(SJ#YPDr=y!)+NI1$B>~w>|yp z#64v;0>($#jb>s2J`Bj*9`ncpFLW+^?S=<*ic4Va1Lw%}koc(|CO!PS{~%kC?JI7q zpp!boYx_yMeH?l?+FSa~j|g@m#nD>4$N}%&fD|CA`73ut@7+8p)cY8Nf+SbCo7^Pt zs{Yv%5P$du<#cW6E6RT-$H%;h! zV>~v7{-L;lx)Rum5PQ?cY=86cRJh?7LH_axo`KXb#Cnl~|LNzkU!k`(#)Uz yt}Wa<%T^mQm*j?pV35xI|Ai9!f1%miosjopludBx%)g=>ZU6VrzvO@F*s_avnfrA%9;Vp+jIhjWuak|ORd>~LvVg(i+_p|dNc-h zR`158;gCWt>FYB2u2w%RKG@R8d*`gHWIA$8=MFZa)Hv4;ggib2UN7~Anj<58Ft zu8*hW=cYc-qUz*CfsFz!{bt zV|e~@EWoq1NZcFAa# zh6z_C83#o65cAFM`Ac<*#sR0XT_H}QsTim6ZMouodnM%e&8m+M*82n>Y;ZraT@ADv z4v>d2+0(etoBDFX0l~-*b?uDp0h{FqI!ZL=>ocB2ta3m>xr&RS-7@L$$L4`;!6+l) z&=+W}A=PE|$TH9c41c~Z)aBr38FjnIkRg$lYOFBXTlW@Ui#xLOCGuCYe`O!ZxO`_- z1~fMHS94kx%RDbpG;h#*DVklQDpXU--|+f7N*lf^%xsDL)+!CI&@`=?Rw)<{u|Q)A z65ks?jcUGdAQgHx)WQD!?)sHmd8S{*F=-uPr$;MG`acyqXHaPr?G)_eyjokpe>N*t zWJ+6ai|p9npoddFPaVfR2$yDkJlKNvbMQZjEikVwj=agw6~gveZy3@th`o~CSp4_r RZ-;bBEkq&__8)*z<5wN5XRQDL diff --git a/tests/resource/objects_attrs.json b/tests/resource/objects_attrs.json index d3be4496..b1144317 100644 --- a/tests/resource/objects_attrs.json +++ b/tests/resource/objects_attrs.json @@ -1 +1 @@ -{"project": "attrs", "version": "17.2", "count": 56, "0": {"name": "attr.Attribute", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "1": {"name": "attr.Factory", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "2": {"name": "attr.asdict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "3": {"name": "attr.assoc", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "4": {"name": "attr.astuple", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "5": {"name": "attr.converters.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "6": {"name": "attr.evolve", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "7": {"name": "attr.exceptions.AttrsAttributeNotFoundError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "8": {"name": "attr.exceptions.DefaultAlreadySetError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "9": {"name": "attr.exceptions.FrozenInstanceError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "10": {"name": "attr.exceptions.NotAnAttrsClassError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "11": {"name": "attr.fields", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "12": {"name": "attr.filters.exclude", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "13": {"name": "attr.filters.include", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "14": {"name": "attr.get_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "15": {"name": "attr.has", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "16": {"name": "attr.ib", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "17": {"name": "attr.make_class", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "18": {"name": "attr.s", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "19": {"name": "attr.set_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "20": {"name": "attr.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "21": {"name": "attr.validators.and_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "22": {"name": "attr.validators.in_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "23": {"name": "attr.validators.instance_of", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "24": {"name": "attr.validators.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "25": {"name": "attr.validators.provides", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "26": {"name": "api", "domain": "std", "role": "doc", "priority": "-1", "uri": "api.html", "dispname": "API"}, "27": {"name": "api", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "API"}, "28": {"name": "api_validators", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#api-validators", "dispname": "Validators"}, "29": {"name": "asdict", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Converting to Collections Types"}, "30": {"name": "backward-compatibility", "domain": "std", "role": "doc", "priority": "-1", "uri": "backward-compatibility.html", "dispname": "Backward Compatibility"}, "31": {"name": "changelog", "domain": "std", "role": "doc", "priority": "-1", "uri": "changelog.html", "dispname": "Changelog"}, "32": {"name": "contributing", "domain": "std", "role": "doc", "priority": "-1", "uri": "contributing.html", "dispname": "How To Contribute"}, "33": {"name": "contributing", "domain": "std", "role": "label", "priority": "-1", "uri": "contributing.html#$", "dispname": "How To Contribute"}, "34": {"name": "examples", "domain": "std", "role": "doc", "priority": "-1", "uri": "examples.html", "dispname": "Examples"}, "35": {"name": "examples", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Examples"}, "36": {"name": "examples_validators", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#examples-validators", "dispname": "Validators"}, "37": {"name": "exemption", "domain": "std", "role": "label", "priority": "-1", "uri": "backward-compatibility.html#$", "dispname": "-"}, "38": {"name": "extending", "domain": "std", "role": "doc", "priority": "-1", "uri": "extending.html", "dispname": "Extending"}, "39": {"name": "extending", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#$", "dispname": "Extending"}, "40": {"name": "extending_metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#extending-metadata", "dispname": "Metadata"}, "41": {"name": "genindex", "domain": "std", "role": "label", "priority": "-1", "uri": "genindex.html", "dispname": "Index"}, "42": {"name": "helpers", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "Helpers"}, "43": {"name": "how", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "How Does It Work?"}, "44": {"name": "how-does-it-work", "domain": "std", "role": "doc", "priority": "-1", "uri": "how-does-it-work.html", "dispname": "How Does It Work?"}, "45": {"name": "how-frozen", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "Immutability"}, "46": {"name": "index", "domain": "std", "role": "doc", "priority": "-1", "uri": "index.html", "dispname": "attrs: Classes Without Boilerplate"}, "47": {"name": "license", "domain": "std", "role": "doc", "priority": "-1", "uri": "license.html", "dispname": "License and Credits"}, "48": {"name": "metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Metadata"}, "49": {"name": "modindex", "domain": "std", "role": "label", "priority": "-1", "uri": "py-modindex.html", "dispname": "Module Index"}, "50": {"name": "overview", "domain": "std", "role": "doc", "priority": "-1", "uri": "overview.html", "dispname": "Overview"}, "51": {"name": "philosophy", "domain": "std", "role": "label", "priority": "-1", "uri": "overview.html#$", "dispname": "Philosophy"}, "52": {"name": "search", "domain": "std", "role": "label", "priority": "-1", "uri": "search.html", "dispname": "Search Page"}, "53": {"name": "slots", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Slots"}, "54": {"name": "why", "domain": "std", "role": "doc", "priority": "-1", "uri": "why.html", "dispname": "Why not\u2026"}, "55": {"name": "why", "domain": "std", "role": "label", "priority": "-1", "uri": "why.html#$", "dispname": "Why not\u2026"}} \ No newline at end of file +{"project": "attrs", "version": "22.1", "count": 129, "0": {"name": "attr", "domain": "py", "role": "module", "priority": "0", "uri": "index.html#module-$", "dispname": "-"}, "1": {"name": "attr.VersionInfo", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "2": {"name": "attr._make.Attribute", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.Attribute", "dispname": "-"}, "3": {"name": "attr._make.Factory", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.Factory", "dispname": "-"}, "4": {"name": "attr._version_info.VersionInfo", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attr.VersionInfo", "dispname": "-"}, "5": {"name": "attr.asdict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "6": {"name": "attr.assoc", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "7": {"name": "attr.astuple", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "8": {"name": "attr.attr.NOTHING", "domain": "py", "role": "data", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "9": {"name": "attr.attr.cmp_using", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "10": {"name": "attr.attr.evolve", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "11": {"name": "attr.attr.fields", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "12": {"name": "attr.attr.fields_dict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "13": {"name": "attr.attr.filters.exclude", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "14": {"name": "attr.attr.filters.include", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "15": {"name": "attr.attr.has", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "16": {"name": "attr.attr.resolve_types", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "17": {"name": "attr.attr.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "18": {"name": "attr.attrs.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "19": {"name": "attr.attrs.mutable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "20": {"name": "attr.attrs.setters.NO_OP", "domain": "py", "role": "data", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "21": {"name": "attr.define", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "22": {"name": "attr.exceptions.AttrsAttributeNotFoundError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.AttrsAttributeNotFoundError", "dispname": "-"}, "23": {"name": "attr.exceptions.DefaultAlreadySetError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.DefaultAlreadySetError", "dispname": "-"}, "24": {"name": "attr.exceptions.FrozenAttributeError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenAttributeError", "dispname": "-"}, "25": {"name": "attr.exceptions.FrozenError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenError", "dispname": "-"}, "26": {"name": "attr.exceptions.FrozenInstanceError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenInstanceError", "dispname": "-"}, "27": {"name": "attr.exceptions.NotAnAttrsClassError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.NotAnAttrsClassError", "dispname": "-"}, "28": {"name": "attr.exceptions.NotCallableError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.NotCallableError", "dispname": "-"}, "29": {"name": "attr.exceptions.PythonTooOldError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.PythonTooOldError", "dispname": "-"}, "30": {"name": "attr.exceptions.UnannotatedAttributeError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.UnannotatedAttributeError", "dispname": "-"}, "31": {"name": "attr.field", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "32": {"name": "attr.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "33": {"name": "attr.get_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "34": {"name": "attr.ib", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "35": {"name": "attr.mutable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "36": {"name": "attr.s", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "37": {"name": "attr.set_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "38": {"name": "attrs", "domain": "py", "role": "module", "priority": "0", "uri": "index.html#module-$", "dispname": "-"}, "39": {"name": "attrs.Attribute", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "40": {"name": "attrs.Attribute.evolve", "domain": "py", "role": "method", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "41": {"name": "attrs.Factory", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "42": {"name": "attrs.NOTHING", "domain": "py", "role": "data", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "43": {"name": "attrs.asdict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "44": {"name": "attrs.astuple", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "45": {"name": "attrs.cmp_using", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "46": {"name": "attrs.converters.default_if_none", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "47": {"name": "attrs.converters.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "48": {"name": "attrs.converters.pipe", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "49": {"name": "attrs.converters.to_bool", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "50": {"name": "attrs.define", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "51": {"name": "attrs.evolve", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "52": {"name": "attrs.exceptions.AttrsAttributeNotFoundError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "53": {"name": "attrs.exceptions.DefaultAlreadySetError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "54": {"name": "attrs.exceptions.FrozenAttributeError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "55": {"name": "attrs.exceptions.FrozenError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "56": {"name": "attrs.exceptions.FrozenInstanceError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "57": {"name": "attrs.exceptions.NotAnAttrsClassError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "58": {"name": "attrs.exceptions.NotCallableError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "59": {"name": "attrs.exceptions.PythonTooOldError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "60": {"name": "attrs.exceptions.UnannotatedAttributeError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "61": {"name": "attrs.field", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "62": {"name": "attrs.fields", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "63": {"name": "attrs.fields_dict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "64": {"name": "attrs.filters.exclude", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "65": {"name": "attrs.filters.include", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "66": {"name": "attrs.has", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "67": {"name": "attrs.make_class", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "68": {"name": "attrs.resolve_types", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "69": {"name": "attrs.setters.convert", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "70": {"name": "attrs.setters.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "71": {"name": "attrs.setters.pipe", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "72": {"name": "attrs.setters.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "73": {"name": "attrs.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "74": {"name": "attrs.validators.and_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "75": {"name": "attrs.validators.deep_iterable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "76": {"name": "attrs.validators.deep_mapping", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "77": {"name": "attrs.validators.disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "78": {"name": "attrs.validators.ge", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "79": {"name": "attrs.validators.get_disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "80": {"name": "attrs.validators.gt", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "81": {"name": "attrs.validators.in_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "82": {"name": "attrs.validators.instance_of", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "83": {"name": "attrs.validators.is_callable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "84": {"name": "attrs.validators.le", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "85": {"name": "attrs.validators.lt", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "86": {"name": "attrs.validators.matches_re", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "87": {"name": "attrs.validators.max_len", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "88": {"name": "attrs.validators.min_len", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "89": {"name": "attrs.validators.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "90": {"name": "attrs.validators.provides", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "91": {"name": "attrs.validators.set_disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "92": {"name": "api", "domain": "std", "role": "doc", "priority": "-1", "uri": "api.html", "dispname": "API Reference"}, "93": {"name": "api_setters", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#api-setters", "dispname": "Setters"}, "94": {"name": "api_validators", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#api-validators", "dispname": "Validators"}, "95": {"name": "asdict", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Converting to Collections Types"}, "96": {"name": "changelog", "domain": "std", "role": "doc", "priority": "-1", "uri": "changelog.html", "dispname": "Changelog"}, "97": {"name": "comparison", "domain": "std", "role": "doc", "priority": "-1", "uri": "comparison.html", "dispname": "Comparison"}, "98": {"name": "converters", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "Converters"}, "99": {"name": "custom-comparison", "domain": "std", "role": "label", "priority": "-1", "uri": "comparison.html#$", "dispname": "Customization"}, "100": {"name": "dict classes", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-dict-classes", "dispname": "-"}, "101": {"name": "dunder methods", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-dunder-methods", "dispname": "-"}, "102": {"name": "examples", "domain": "std", "role": "doc", "priority": "-1", "uri": "examples.html", "dispname": "attrs by Example"}, "103": {"name": "examples_validators", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#examples-validators", "dispname": "Validators"}, "104": {"name": "extending", "domain": "std", "role": "doc", "priority": "-1", "uri": "extending.html", "dispname": "Extending"}, "105": {"name": "extending_metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#extending-metadata", "dispname": "Metadata"}, "106": {"name": "genindex", "domain": "std", "role": "label", "priority": "-1", "uri": "genindex.html", "dispname": "Index"}, "107": {"name": "glossary", "domain": "std", "role": "doc", "priority": "-1", "uri": "glossary.html", "dispname": "Glossary"}, "108": {"name": "hashing", "domain": "std", "role": "doc", "priority": "-1", "uri": "hashing.html", "dispname": "Hashing"}, "109": {"name": "helpers", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "Helpers"}, "110": {"name": "how", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "How Does It Work?"}, "111": {"name": "how-does-it-work", "domain": "std", "role": "doc", "priority": "-1", "uri": "how-does-it-work.html", "dispname": "How Does It Work?"}, "112": {"name": "how-frozen", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "Immutability"}, "113": {"name": "index", "domain": "std", "role": "doc", "priority": "-1", "uri": "index.html", "dispname": "attrs: Classes Without Boilerplate"}, "114": {"name": "init", "domain": "std", "role": "doc", "priority": "-1", "uri": "init.html", "dispname": "Initialization"}, "115": {"name": "license", "domain": "std", "role": "doc", "priority": "-1", "uri": "license.html", "dispname": "License and Credits"}, "116": {"name": "metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Metadata"}, "117": {"name": "modindex", "domain": "std", "role": "label", "priority": "-1", "uri": "py-modindex.html", "dispname": "Module Index"}, "118": {"name": "names", "domain": "std", "role": "doc", "priority": "-1", "uri": "names.html", "dispname": "On The Core API Names"}, "119": {"name": "overview", "domain": "std", "role": "doc", "priority": "-1", "uri": "overview.html", "dispname": "Overview"}, "120": {"name": "philosophy", "domain": "std", "role": "label", "priority": "-1", "uri": "overview.html#$", "dispname": "Philosophy"}, "121": {"name": "py-modindex", "domain": "std", "role": "label", "priority": "-1", "uri": "py-modindex.html", "dispname": "Python Module Index"}, "122": {"name": "search", "domain": "std", "role": "label", "priority": "-1", "uri": "search.html", "dispname": "Search Page"}, "123": {"name": "slotted classes", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-slotted-classes", "dispname": "-"}, "124": {"name": "transform-fields", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#$", "dispname": "Automatic Field Transformation and Modification"}, "125": {"name": "types", "domain": "std", "role": "doc", "priority": "-1", "uri": "types.html", "dispname": "Type Annotations"}, "126": {"name": "validators", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "Validators"}, "127": {"name": "version-info", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "-"}, "128": {"name": "why", "domain": "std", "role": "doc", "priority": "-1", "uri": "why.html", "dispname": "Why not\u2026"}} \ No newline at end of file diff --git a/tests/resource/objects_attrs.txt b/tests/resource/objects_attrs.txt index 1296a6a9..50cf9464 100644 --- a/tests/resource/objects_attrs.txt +++ b/tests/resource/objects_attrs.txt @@ -1,60 +1,133 @@ # Sphinx inventory version 2 # Project: attrs -# Version: 17.2 +# Version: 22.1 # The remainder of this file is compressed using zlib. -attr.Attribute py:class 1 api.html#$ - -attr.Factory py:class 1 api.html#$ - +attr py:module 0 index.html#module-$ - +attr.VersionInfo py:class 1 api.html#$ - +attr._make.Attribute py:class -1 api.html#attrs.Attribute - +attr._make.Factory py:class -1 api.html#attrs.Factory - +attr._version_info.VersionInfo py:class -1 api.html#attr.VersionInfo - attr.asdict py:function 1 api.html#$ - attr.assoc py:function 1 api.html#$ - attr.astuple py:function 1 api.html#$ - -attr.converters.optional py:function 1 api.html#$ - -attr.evolve py:function 1 api.html#$ - -attr.exceptions.AttrsAttributeNotFoundError py:exception 1 api.html#$ - -attr.exceptions.DefaultAlreadySetError py:exception 1 api.html#$ - -attr.exceptions.FrozenInstanceError py:exception 1 api.html#$ - -attr.exceptions.NotAnAttrsClassError py:exception 1 api.html#$ - -attr.fields py:function 1 api.html#$ - -attr.filters.exclude py:function 1 api.html#$ - -attr.filters.include py:function 1 api.html#$ - +attr.attr.NOTHING py:data 1 api.html#$ - +attr.attr.cmp_using py:function 1 api.html#$ - +attr.attr.evolve py:function 1 api.html#$ - +attr.attr.fields py:function 1 api.html#$ - +attr.attr.fields_dict py:function 1 api.html#$ - +attr.attr.filters.exclude py:function 1 api.html#$ - +attr.attr.filters.include py:function 1 api.html#$ - +attr.attr.has py:function 1 api.html#$ - +attr.attr.resolve_types py:function 1 api.html#$ - +attr.attr.validate py:function 1 api.html#$ - +attr.attrs.frozen py:function 1 api.html#$ - +attr.attrs.mutable py:function 1 api.html#$ - +attr.attrs.setters.NO_OP py:data 1 api.html#$ - +attr.define py:function 1 api.html#$ - +attr.exceptions.AttrsAttributeNotFoundError py:exception -1 api.html#attrs.exceptions.AttrsAttributeNotFoundError - +attr.exceptions.DefaultAlreadySetError py:exception -1 api.html#attrs.exceptions.DefaultAlreadySetError - +attr.exceptions.FrozenAttributeError py:exception -1 api.html#attrs.exceptions.FrozenAttributeError - +attr.exceptions.FrozenError py:exception -1 api.html#attrs.exceptions.FrozenError - +attr.exceptions.FrozenInstanceError py:exception -1 api.html#attrs.exceptions.FrozenInstanceError - +attr.exceptions.NotAnAttrsClassError py:exception -1 api.html#attrs.exceptions.NotAnAttrsClassError - +attr.exceptions.NotCallableError py:exception -1 api.html#attrs.exceptions.NotCallableError - +attr.exceptions.PythonTooOldError py:exception -1 api.html#attrs.exceptions.PythonTooOldError - +attr.exceptions.UnannotatedAttributeError py:exception -1 api.html#attrs.exceptions.UnannotatedAttributeError - +attr.field py:function 1 api.html#$ - +attr.frozen py:function 1 api.html#$ - attr.get_run_validators py:function 1 api.html#$ - -attr.has py:function 1 api.html#$ - attr.ib py:function 1 api.html#$ - -attr.make_class py:function 1 api.html#$ - +attr.mutable py:function 1 api.html#$ - attr.s py:function 1 api.html#$ - attr.set_run_validators py:function 1 api.html#$ - -attr.validate py:function 1 api.html#$ - -attr.validators.and_ py:function 1 api.html#$ - -attr.validators.in_ py:function 1 api.html#$ - -attr.validators.instance_of py:function 1 api.html#$ - -attr.validators.optional py:function 1 api.html#$ - -attr.validators.provides py:function 1 api.html#$ - -api std:doc -1 api.html API -api std:label -1 api.html#$ API +attrs py:module 0 index.html#module-$ - +attrs.Attribute py:class 1 api.html#$ - +attrs.Attribute.evolve py:method 1 api.html#$ - +attrs.Factory py:class 1 api.html#$ - +attrs.NOTHING py:data 1 api.html#$ - +attrs.asdict py:function 1 api.html#$ - +attrs.astuple py:function 1 api.html#$ - +attrs.cmp_using py:function 1 api.html#$ - +attrs.converters.default_if_none py:function 1 api.html#$ - +attrs.converters.optional py:function 1 api.html#$ - +attrs.converters.pipe py:function 1 api.html#$ - +attrs.converters.to_bool py:function 1 api.html#$ - +attrs.define py:function 1 api.html#$ - +attrs.evolve py:function 1 api.html#$ - +attrs.exceptions.AttrsAttributeNotFoundError py:exception 1 api.html#$ - +attrs.exceptions.DefaultAlreadySetError py:exception 1 api.html#$ - +attrs.exceptions.FrozenAttributeError py:exception 1 api.html#$ - +attrs.exceptions.FrozenError py:exception 1 api.html#$ - +attrs.exceptions.FrozenInstanceError py:exception 1 api.html#$ - +attrs.exceptions.NotAnAttrsClassError py:exception 1 api.html#$ - +attrs.exceptions.NotCallableError py:exception 1 api.html#$ - +attrs.exceptions.PythonTooOldError py:exception 1 api.html#$ - +attrs.exceptions.UnannotatedAttributeError py:exception 1 api.html#$ - +attrs.field py:function 1 api.html#$ - +attrs.fields py:function 1 api.html#$ - +attrs.fields_dict py:function 1 api.html#$ - +attrs.filters.exclude py:function 1 api.html#$ - +attrs.filters.include py:function 1 api.html#$ - +attrs.has py:function 1 api.html#$ - +attrs.make_class py:function 1 api.html#$ - +attrs.resolve_types py:function 1 api.html#$ - +attrs.setters.convert py:function 1 api.html#$ - +attrs.setters.frozen py:function 1 api.html#$ - +attrs.setters.pipe py:function 1 api.html#$ - +attrs.setters.validate py:function 1 api.html#$ - +attrs.validate py:function 1 api.html#$ - +attrs.validators.and_ py:function 1 api.html#$ - +attrs.validators.deep_iterable py:function 1 api.html#$ - +attrs.validators.deep_mapping py:function 1 api.html#$ - +attrs.validators.disabled py:function 1 api.html#$ - +attrs.validators.ge py:function 1 api.html#$ - +attrs.validators.get_disabled py:function 1 api.html#$ - +attrs.validators.gt py:function 1 api.html#$ - +attrs.validators.in_ py:function 1 api.html#$ - +attrs.validators.instance_of py:function 1 api.html#$ - +attrs.validators.is_callable py:function 1 api.html#$ - +attrs.validators.le py:function 1 api.html#$ - +attrs.validators.lt py:function 1 api.html#$ - +attrs.validators.matches_re py:function 1 api.html#$ - +attrs.validators.max_len py:function 1 api.html#$ - +attrs.validators.min_len py:function 1 api.html#$ - +attrs.validators.optional py:function 1 api.html#$ - +attrs.validators.provides py:function 1 api.html#$ - +attrs.validators.set_disabled py:function 1 api.html#$ - +api std:doc -1 api.html API Reference +api_setters std:label -1 api.html#api-setters Setters api_validators std:label -1 api.html#api-validators Validators asdict std:label -1 examples.html#$ Converting to Collections Types -backward-compatibility std:doc -1 backward-compatibility.html Backward Compatibility changelog std:doc -1 changelog.html Changelog -contributing std:doc -1 contributing.html How To Contribute -contributing std:label -1 contributing.html#$ How To Contribute -examples std:doc -1 examples.html Examples -examples std:label -1 examples.html#$ Examples +comparison std:doc -1 comparison.html Comparison +converters std:label -1 init.html#$ Converters +custom-comparison std:label -1 comparison.html#$ Customization +dict classes std:term -1 glossary.html#term-dict-classes - +dunder methods std:term -1 glossary.html#term-dunder-methods - +examples std:doc -1 examples.html attrs by Example examples_validators std:label -1 examples.html#examples-validators Validators -exemption std:label -1 backward-compatibility.html#$ - extending std:doc -1 extending.html Extending -extending std:label -1 extending.html#$ Extending extending_metadata std:label -1 extending.html#extending-metadata Metadata genindex std:label -1 genindex.html Index +glossary std:doc -1 glossary.html Glossary +hashing std:doc -1 hashing.html Hashing helpers std:label -1 api.html#$ Helpers how std:label -1 how-does-it-work.html#$ How Does It Work? how-does-it-work std:doc -1 how-does-it-work.html How Does It Work? how-frozen std:label -1 how-does-it-work.html#$ Immutability index std:doc -1 index.html attrs: Classes Without Boilerplate +init std:doc -1 init.html Initialization license std:doc -1 license.html License and Credits metadata std:label -1 examples.html#$ Metadata modindex std:label -1 py-modindex.html Module Index +names std:doc -1 names.html On The Core API Names overview std:doc -1 overview.html Overview philosophy std:label -1 overview.html#$ Philosophy +py-modindex std:label -1 py-modindex.html Python Module Index search std:label -1 search.html Search Page -slots std:label -1 examples.html#$ Slots +slotted classes std:term -1 glossary.html#term-slotted-classes - +transform-fields std:label -1 extending.html#$ Automatic Field Transformation and Modification +types std:doc -1 types.html Type Annotations +validators std:label -1 init.html#$ Validators +version-info std:label -1 api.html#$ - why std:doc -1 why.html Why not… -why std:label -1 why.html#$ Why not… diff --git a/tests/resource/objects_attrs_17_2_0.inv b/tests/resource/objects_attrs_17_2_0.inv new file mode 100644 index 0000000000000000000000000000000000000000..b648b4b88261e619e88b7f64e50596566d28270a GIT binary patch literal 834 zcmV-I1HJqsAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkmbaZla z3L_v^WpZ8b#rNMXCQiPX<{x4c-obg&2HN;49D+!3IW^I0e0avnfrA%9;Vp+jIhjWuak|ORd>~LvVg(i;5C@GzNB7 z@5ZI!kU}l#>oWPSRzEC0*wV;*=d7z_I&w_s4mP6HIM)t@JU#f}U$jRGzGXvsE8*R3EiT}qhDD>IGX0HH zF5X}j?*14$fw=w{4GL31(wqq+SJ&{$T#1J}xU!pT!Y03_QB2|NPD!|2rb2O#@Y{t(8`Ij8Al)2#36Fd?XzCSegm51#P#nPG=0Ei+0IqmWBye zB^d`q_7L;U?)gh~ipBw_v0WifqNy0C@ol-{eS0P3_sy!04%YhwA8c?xvRw_d8V-<$ zG1=3&(3|>l!U4g^4|VN~?E#zR2RceL=Ib+_M67Z^LAi>Hq1`g+@WHY-+SN?UJ> z?AYI+hf_XJ9mhNfmu7uD*n;+R@IQ$yFt06+yvffM!uDBj7}7F`y^`Hn{P*W?hjdCU ML?RLPAAnKgS82bA-~a#s literal 0 HcmV?d00001 diff --git a/tests/resource/objects_sphinx.inv b/tests/resource/objects_sphinx.inv index 14e4893652ff7934427e70942a5537bdcff0b908..ed2fe5b49dea079c6de5789bf7e6d5695944f23b 100644 GIT binary patch literal 14192 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 G(=kkTBdzKH delta 9644 zcmV;dB~#k)ZpurLItDQ=HZC?RkwH3ty;GbFwbKm!CCjYi|g z+ncIv9TO#0N!uuENfWo#T3LS5s9yeu4!&pHKV-CBq4@)^&WEaLNvg{s z$zw`qYx1|BKD00Y^aG*v;S!f`s-lL9A9Hg5?&ZV%{mVZZdEJDymc_K#nB@c3)uPfr zcdb=LzwQ&idiAcf6V6XxGr-q>EdBim4?-At>?ASA_b^n#j)?O}fPSXH@2CC6m%j`zs-YZKS?dM(-a zCeproW!txZ`lEpGyzeI*4l>rM27wp}eS~eBf%8XUkV2eZ<1*pn$f+xTlQyf$#c}FS z@8rn)?#p-W{rw*W!(ZUnzz4N&9S6V_V%ny!UX8}>3SQUke04vx|Jft%Cmj4w7x5YS z-l@}=MUjSjju{+B)0{o097nIlRxx^CIk!G+CP^kRRX+(q5|6ksu|abCCw;2yG3o4tfj0H+GZ^;;&QsK&2oAGwUCmA9va$eB^Hed)qm{jxXvbJ zH!&REW(@(UT#4ap9#O4x9OCBO6{Kug)AYS)3*#}blE#L4t}Jcp{Pw)nkE)^BHHZNG{A+uaX-Emw6T5Jq9RT%PGuy;k)$a}S7r-RLJK#d zyvoGa!W`LTajvAKNnDSU%}%G}88utkE!QUBQ+&-}fLSSj>j~!Ph<2w__Pmy|%X2v* ztmZ9hV^vTb32D_e$=WOo2~$3$t3ov-%;WOh#pg9Xm~h*ut0Bc|lj2(7S)1|MlgTs> z+FZ3lRY0z!iPBZ&q`>ahScwq6{dkoP`h0w*>&ajgvCEW;!Xl+@w<(3Du~5G1_|cZF zh8`d~mR%2jN5F{OoUD=K_hPE{(pDCowI*c>4-O7EvuB*X}m^ZFD3(j*9drsk4NY#S_ zak9UP0}J+QRgdoieVQ+Y!`to+bU*J)ZgCwaGL$ z1t0F8VFbq_+)I0PzxEo+pwi9oa9gmU{MJ~16iS5ZEvy$JT&12#D~9Otg5Qgi*&_Df zQ>@I}h`8}Ly2g1&c3^8@OoT7CAC|Y#rK-htC#tBeB5o7kfpjMxVZu1(B*IT^55g<7 zY@S1vs~tKCxe5(y8x5@YNRxruQRO?-5tBvjg%mq*u_<-Wp7Alh#(cT6or~E%K;KJ$ z9)*!*BOQ6(W8m1QqgF>;{q8he)D;D)CNAlzYKrZA`}9*}*|Td=5;w^uQmt+q3AxdR z+irKDYj3c=zYwxR*WalzVUjC_k;R{6b}QbI;>(R38QrBiq{wz)0A01Apmx$O-^e!S zZD7w(fg;;vDcR*q6FW!|?R83jE=t6Iu$0G}r(@vi>WD~RM00ntw zYtDio2Y=a#Ph`)`It*r?x%BuiOJG=E@fIA@Z7D9-bJ zh|q5!J7vi}Y<$yiE7u7=ZF zJ^0!fEf{;S&5f%r919*UE;MyRa8odPLgz~JnCC)AySiql4Wg{TJxpAS&>f12#Upa# z*{6UwxRDFVYroN{haX4M zq3=WQEwUeX)wPPl@qWB~pN;PfZqlVZ+4dorDfh1Hz8^#zmnqD$A$j;=mVC_+qyKzvZ)=6g#N8yq}!FqhEu}^X=3OpIZMZf@2TAwBFN$iNRa; zMlwIK8>x1ZIE;XQy)%rn$OZWD!2k6Ux|zdU>@#$Jf}bJVPxP&~+*>SE>nm{$y+zhK zk++m}nw{kP>}$t*#$`4oU0VIkQ{^`?c#GLc<|k?+)qdhWY?0SalG;T^yGe(icyK?l zBEsan>EU+1Y9juQDL?*dAxjy%=WXxMILdRxFbh2}oed9vd(e!wq)cumrv!VpoW#wX zYlAgQ8kgsMe5%^ubm2hA&!=tWh{TDg&0I^zSKL`P%LiS7Fs?-O2~RmeK z2F0BC>1H1Mj<=U6E7L65E-Z9-%HllQqf_Pak>p!R3eudVZ?i0vw~!WGv8*|ivm2YG zT{ji98Qna8rbr&>+4CGx@qN{m*?!PgPeAuDv^v;u-pXg(<~{vLsItWqVj7q#<#-7iB~8Q@LyRTs%nNL&)OT?AeLtj@%47d5-(Vs&g_*W5(Nwa=d!S5T|=Vm{imTRtng;&MJ1VS>6Z z{y9#6EdD*hR0#Z*NEd>FpSs%xe@LKXoGTu}#{SThAbP-~_x|PhD_>*(g`cy;7WUzK z2IYx|))=?x7vlMBiw@Akk+e^Qlrxbbdy*M+(zPst5%s`R!XwSd1>&RzYJ#<@h?sn4 z9yMN{nIgdhwBsE&#LE{pVE9D%ALhexBd!sD394~q8teHB@q8(N_w6{5i5X5t4ou zUUuA^M}``oGTteROI)Toi9U6txqS|P+`{;*71*ofxL5;~@B{z%n>cwSWjg79?)>eM zzxC%m#0f4hW{1c9@>v*zcg4#yz%W0-b}m!3R%)i;RfHd^Ao!z66=W1G$> z>%~$Oane-2kd+eg%Q+m$2h0jPi$3YZ-6K|*uZ~U0q63p@R}}*R#(Xz_;y?ii+4W&_ z$YGT}MM8JHRLvZ+$Y^3lLI*BW+u;hYc^r*yGeYYxBy|y-23qGAw^q95pukr1z?ijS~Ap{_$79Zne@Q0uIdfo zj$T~R&Lg3US(S+EXsAGc7P(V$io3iGMchw^EK&mcdctm`avXB;@(IwroTQbWO55Qw z&G3cCK8(g8>1T&U#yb-47_>r6STg?|+w`$}WO(9EGde^;1?57PY8}wMa+zLOBW-(8hUT zp(ZNCrhGTc=|gk&aw*TvefrQaYo%f--G^61RwZri^5`0Wyie49oRvmiPsm!iQj%28 zOKTP9B{%Y%Se0(xbi2%NH)*Sm8E*V`llHK6;mB??X%D_FZsah2T9M=B*;(RVeutsF zA!qVzJq|V}>m{Zr?s`4-db!k6GW%kdi`5;QEO8y`X@>53cIkx@&!q>~7Uq8XMz9@CNTu4CUpt zC=~#=7x?3@4|N}MO_%C)YJpz_KZ_(M7+hFn`~c(C1pEUTsG?)XJdv{0w)$fva}n^w z%58L4I1UeZhj4Vt<1_V#XDRfVtiAa&u+wL*=#*R|n0b9_o@SI?7D+_-t%&tFXPPYW z$eRa$#Eju9$AdIpXwvve?C}_hMVJq?YjS5;UL|qv-m#0UjBuWea#Ef>D%y|&4@&x! z7-qj3jXds6!+mlrQA}UqdEk}<3_Riyk5w&h;uX)d1hho>z4H}7EE#v5BQ~Ri|b)*;H zk%pH(f<7hc;EJ!3$0#e%*UYOLLNCZDJ2>Xbpq`(C(Sw|_=fUII%r!l7H6i8BJ5e9W zV1`Kb@liRBG0hUOT^Vu(K>s$h<;aWR8%!Vk$P(T$@4`@Qg)Ged4;R9NAc^N)!-Fq> zquL@!aBXI{kDRqdFQK(O@&R8DT8@znTKO&X%Fvqzz{Axw|A z|N0u^ZdgwG=Q^kt`#93n46uc^X4e&u;P^~&82pAO4S3Q!*-aMv2R8MafCu*g1P|}A z1eofVZvtjRL$?sfR9tqX$VOiA!$c#0?)eFzSbW&l5JP`dFqr8Sg?>xqImYPV)TkB@ zy9+QwT&gE5Dq9vx)LnnvH-uK!ITj8Ct1&!=)8((9lH)1;(6WBM0g@8_OY=zuQ>&D%g_)^_&Qnb1+|n z?#pkK_G9AL=HbpE^VxRdsB4RPQC$%cVc*C1RjGY;$RgS^}8yz$~VKY^%Qzj zqWyv?C=O_5@NmyqdQ8#oNI~y^?+k_nqg~>InqIO*y-~v^WA1Q;qfuSuS#leRnq1Fa zHjMdihx7qY4;0t1zyFvTM|>vJf#OQ?s>Yc^fnn>5St#WR)PYbu(#Jvm42Q8hS#|dH@;GrK__dy%S$s>H*(m8E)5u}-A zwT>nT`0XZrG<7iO{L2*~v((>Nl&5?ENRppJ~bGrh*ZKl-KY`U})iD zXLbjB2_l-sX${pltxoVWfp1?#7ji?g;5{Kb?e2uDJH(+lonRs;krSv_*e$vVUXd4` z;!k?(!GnGQ00{!DE>G%cOGk{fqT}C@*ub-!1Q`NjMmSi_8AhCc-s@Votmf4070{J9 z<-$FphuO&zMxL2_S!CKxSp=dbhsA$(LJiZlC4lb^oH93ISA*dk!Dj|On3vbCt&@3Fy9V zt%{h5&asA|@U=UCm8`Sg_2bDY;cFHbkhrQH*O=C2yH2eO#^@_z4o+a!4LImd7>A;B zRh`HCtvn`_`d&;m{8=b4_xxw@9sl`(9cq5hmDIP=us-Bec13-g&xpO&^Wg}Y%}-tN z{N7UK)P(mxEt*a7;{&)4T6~vZR>*g% zt!2!i*HQw%vQpfIdr3j_*N+;Vbx0BOXnu4n>7a5!XsV7M}?Ytk}KNaLK;qey`%m>&DI(lq!^ zK45P+YkwSQ#HyVH3QSS<)B!{8E~7f02HZG3Sj_LnG4v*xjpOSDbCLP@2f=;?LT!a6 zf?>3&>L$a_SX{A!>x+KlXmo67lKtpJQLqx4Pp!F1E8ffehCqCi{PZ|{!A$%<%m?p; z!zzk@fUshc`R8x{Fnp+e1in#zS^&Pl6tYkD5WSDH-p`HDnCecR-5B%t=Q-f3!M7s% z+OR{V#?>2xwRn4hDMB9>PDXUYX62tgo|^wojz~BPjAp3zk~L`^H|=Cp8Q#ckCiorl zq@$6WxfYJ$(m^m7M+6)fls#md8+U4)zcHbI7XL3WMGTb9)3-{0WDpnsdJ7F|#VDVV zzQH`%GGP=(!;VNIJ{mKAcsa~_xW%mC)qO$(!(bmMYawrN!PhAeErp zyc&UO98nksHC-nd%;W3EaXn0;flLjc82liTDTUzs2L253FL?g#|(Fs>dnIiUlC zjijVGPl!kw^JM+Lef`VblEqI=h7&x0>5VkQ_1<>UI5mV`Lip$$wyn>k96rasc=9Q) z2)iByQnu_ScIdhpI~$NkZQPtmYui{o0SHyZB69;KRZ+**PL>jdzLE~cKMCvX?GODa zdZia=_TS(;@k>uSh+8ujznCTu_5HH(X6WF9u40958l{!Vqf9?v{T`2mw*wtJ)0NqSy_#hPXXgDlBtTq4`*3nGQmLR1=V~ zX&_vxu=*j_4(4ix6`x{+hdvyELnW;t_08wEyy&3w8VHN8n=0Y9hCt&y-xIGCz|%ZN6s zO(a7Q5)(MRX7ywYw}s7>dlgHs=fW4~m+1)<92j)|PMndvt!DM*WpEDj__H6%ubv!Q zHzY2OxqD^tGXgLg#6MTd<&sZ-b=Oz zFv-q9T$hvC3{g{!%Gy+YVf&y#knpNnNczgRUqKI|PT4oVe#l%JcMq$})s?J;?RR(X3{SL)W9r4M3iRs+3`Kn*&__28|l<7)gmrk=K+9p zP#hL1Q_Kc`@aPL|_Eu-U$xC%_U#3?`RkmTTX-dZ4X`BAq6a~98e!sW^f)v1$n?yC>3+pBat=_RYa6S= zq3q3YK3rS$7&-dY&}dzw1Q#>l`j}(EkMI}CL5+id@1KsqxC>_h_nULLWgoLOW60*B z5nP7rnlh-7y4V!)@bjAhp8%AiRY(gQv2X%~C+|-=vCe@{BKfh|^rrR_N`It@U-6(R zznJq}Vv4pfSj&~9jk+zaC3Vx$3)03c)TL={JVcUv5qt|1ZTN&oFeKy-UZam}s5sBs zZp;;bxL+~ZRIhKLd?7j$kI%@r*X1j(Be&ACOZbdNdSDq{Qu=kQMivoTIbs*}J!NPT zn{*IIs=CRpcyHG}Y_ujx2J3}wY|IIEtE^Bnj8kYawuV9TU8K3U??H%BllNomJM;$1 z3?4QJcVNRP?&`@>es?rLOZK$}xYi+FL4Ss9v zjH-p_8hk|3+1Vmvme_3LUcvBf&dBAkk_ZKEaV(Sj*3GKElPjGS=es&RI;@mn7-SKe zl!L|V^$zke}HfJ;R+$e~4p$&h@@-AsJ&ANtgH!a>VA0u)cLg?<_y zIeh2>;V z7%ElqkxOdd^U_6-^JGoBuAw=+$6P>uTB;%1j*u`}IQZR8%b1bW{l`9pGOxh{s z>s7KW{nHfo?as3N-ka|-CHv8vteBGh#ha{|l0EF%bbs|GyH3esZ?bqwmU@$=Q?k>Z z<3PUWFtzJoT6vRIQ!@W?NEvm1xLG?4(dW#ak4IF!OzE_c=zB2Q3}IhQP;V?yFDIzC z7N{>LsC(bak_pvM76tf^3F^IX0qP0WFBS#(dV+eeK>cxo`qcvUhY2e7t!zA@I{H!_ zCsc_qRWhMUeW}t3)n&iW@S`u)#|f49;80GeKKW98nozaARPBW7>PvNholrgbQaue+ z%7$YYs^Pv|SO*gIL(-^^ahqJ2Kf)IFfyJCle^$+tAMs{p78-2}H6xheer`iGNQ`$D z3eS8_TJV!CS@lHod8x5bwqzxF=5x}*W^Bo-CtAphJ0Wk+O7JY?G>TcVDK~{{K1Z=n zx;Zz=GoMo*%3(`3jATB44=uvOmVA1m*}Sx!9sispjX57beO$?5uCwW$rJm&Z3_0F_ zyLssEN#^pP{Q(#692kX}zpVa6Qy66QuaFmH(^0}wg~iq{L}xN*sO>^|=2Opb!w<5J z`O^%uwsYjkJ=diu+4e0Xeui1G7WIr&6{y6wXJikNF!G=)kdcBfCGiOiD2MaJ@$nOL%hqUKl>%2R<{84 zaP2A}7FL=Scy6%&A0?PKtJ*(*`@cK$Rm)4gS=w`;to+L1-n^?dz7`48Ou(-Ib;64N z9cDB%UH-XLZd8Fr@g2pZ;dsZd62WQ|+veQl~Lc)h<=&prx9@6K7ww9mHU3Y6$@! zwTH$sY7rotZIcT@Kf~ejF*$UGaf6csQ;fv;yKn?vy^icx!Eh%oHwewQgPP;dii cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0E5OuterIP1TE - +Outer::T cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0E5OuterIP1TE - +Outer cpp:class 1 usage/restructuredtext/domains.html#_CPPv4IE5OuterIiE - +Outer::Inner cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0EN5OuterIiE5InnerE - +Outer::Inner::TInner cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EN5OuterIiE5InnerE - +Outer::Inner cpp:class 1 usage/restructuredtext/domains.html#_CPPv4IEN5OuterIiE5InnerIbEE - +Wrapper cpp:class 1 usage/restructuredtext/domains.html#_CPPv47$ - +Wrapper::Outer cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0EN7Wrapper5OuterE - +Wrapper::Outer::Inner cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0EN7Wrapper5Outer5InnerE - +Wrapper::Outer::Inner::TInner cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EN7Wrapper5Outer5InnerE - +Wrapper::Outer::TOuter cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EN7Wrapper5OuterE - +a cpp:member 1 usage/restructuredtext/domains.html#_CPPv41$ - +advance cpp:function 1 usage/restructuredtext/domains.html#_CPPv4I0EXNSt8IteratorEI2ItEE7advancevR2It - +advance::It cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EXNSt8IteratorEI2ItEE7advancevR2It - +advance::it cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv4I0EXNSt8IteratorEI2ItEE7advancevR2It - +f cpp:function 1 usage/restructuredtext/domains.html#_CPPv41fi - +f::i cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv41fi - +overload_example::C cpp:class 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1CE - +overload_example::C::f cpp:function 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEd - +overload_example::C::f cpp:function 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEi - +overload_example::C::f cpp:function 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEv - +overload_example::C::f cpp:function 1 usage/restructuredtext/domains.html#_CPPv4NK16overload_example1C1fEd - +overload_example::C::f::d cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEd - +overload_example::C::f::d cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv4NK16overload_example1C1fEd - +overload_example::C::f::i cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEi - +std::Iterator cpp:concept 1 usage/restructuredtext/domains.html#_CPPv4I0ENSt8IteratorE - +std::Iterator::It cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0ENSt8IteratorE - +std::Iterator::r cpp:member 1 usage/restructuredtext/domains.html#_CPPv4NSt8Iterator1rE - +attributes py:data 1 usage/extensions/autosummary.html#$ - +body py:data 1 templating.html#$ - +builder py:data 1 templating.html#$ - +class py:data 1 usage/extensions/autosummary.html#$ - +classes py:data 1 usage/extensions/autosummary.html#$ - +conf py:module 0 usage/configuration.html#module-$ - +copyright py:data 1 templating.html#$ - +display_toc py:data 1 templating.html#$ - +docstitle py:data 1 templating.html#$ - +docutils.nodes.meta py:class -1 extdev/nodes.html#sphinx.addnodes.meta - +docutils.parsers.rst py:module 0 extdev/markupapi.html#module-$ - +docutils.parsers.rst.Directive py:class 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.arguments py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.block_text py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.content py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.content_offset py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.final_argument_whitespace py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.has_content py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.lineno py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.name py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.option_spec py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.optional_arguments py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.options py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.required_arguments py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.run py:method 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.state py:attribute 1 extdev/markupapi.html#$ - +docutils.parsers.rst.Directive.state_machine py:attribute 1 extdev/markupapi.html#$ - +docutils_version_info py:data 1 templating.html#$ - +embedded py:data 1 templating.html#$ - +enumerate py:function 1 usage/quickstart.html#$ - +escape py:function 1 usage/extensions/autosummary.html#$ - +exceptions py:data 1 usage/extensions/autosummary.html#$ - +favicon_url py:data 1 templating.html#$ - +file_suffix py:data 1 templating.html#$ - +fullname py:data 1 usage/extensions/autosummary.html#$ - +functions py:data 1 usage/extensions/autosummary.html#$ - +has_source py:data 1 templating.html#$ - +hasdoc py:function 1 templating.html#$ - +inherited_members py:data 1 usage/extensions/autosummary.html#$ - +language py:data 1 templating.html#$ - +last_updated py:data 1 templating.html#$ - +latex py:module 0 latex.html#module-$ - +logo_url py:data 1 templating.html#$ - +master_doc py:data 1 templating.html#$ - +members py:data 1 usage/extensions/autosummary.html#$ - +meta py:data 1 templating.html#$ - +metatags py:data 1 templating.html#$ - +methods py:data 1 usage/extensions/autosummary.html#$ - +module py:data 1 usage/extensions/autosummary.html#$ - +modules py:data 1 usage/extensions/autosummary.html#$ - +name py:data 1 usage/extensions/autosummary.html#$ - +next py:data 1 templating.html#$ - +objname py:data 1 usage/extensions/autosummary.html#$ - +page_source_suffix py:data 1 templating.html#$ - +pagename py:data 1 templating.html#$ - +parents py:data 1 templating.html#$ - +pathto py:function 1 templating.html#$ - +prev py:data 1 templating.html#$ - +project py:data 1 templating.html#$ - +relbar py:function 1 templating.html#$ - +reldelim1 py:data 1 templating.html#$ - +reldelim2 py:data 1 templating.html#$ - +release py:data 1 templating.html#$ - +rellinks py:data 1 templating.html#$ - +root_doc py:data 1 templating.html#$ - +script_files py:data 1 templating.html#$ - +shorttitle py:data 1 templating.html#$ - +show_source py:data 1 templating.html#$ - +sidebar py:function 1 templating.html#$ - +sourcename py:data 1 templating.html#$ - +sphinx.addnodes py:module 0 extdev/nodes.html#module-$ - +sphinx.addnodes.compact_paragraph py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_addname py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_annotation py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_content py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_inline py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_name py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_optional py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_parameter py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_parameterlist py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_returns py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_signature py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_signature_line py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.desc_type py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.download_reference py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.glossary py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.highlightlang py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.index py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.literal_emphasis py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.meta py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.only py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.pending_xref py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.pending_xref_condition py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.production py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.productionlist py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.seealso py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.start_of_file py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.toctree py:class 1 extdev/nodes.html#$ - +sphinx.addnodes.versionmodified py:class 1 extdev/nodes.html#$ - +sphinx.application py:module 0 extdev/appapi.html#module-$ - +sphinx.application.ExtensionError py:exception 1 extdev/appapi.html#$ - +sphinx.application.Sphinx py:class 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_autodoc_attrgetter py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_autodocumenter py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_builder py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_config_value py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_crossref_type py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_css_file py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_directive py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_directive_to_domain py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_domain py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_enumerable_node py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_env_collector py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_event py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_generic_role py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_html_math_renderer py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_html_theme py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_index_to_domain py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_js_file py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_latex_package py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_lexer py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_message_catalog py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_node py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_object_type py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_post_transform py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_role py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_role_to_domain py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_search_language py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_source_parser py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_source_suffix py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.add_transform py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.confdir py:attribute 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.connect py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.disconnect py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.doctreedir py:attribute 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.emit py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.emit_firstresult py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.is_parallel_allowed py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.outdir py:attribute 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.project py:attribute 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.require_sphinx py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.set_translator py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.setup_extension py:method 1 extdev/appapi.html#$ - +sphinx.application.Sphinx.srcdir py:attribute 1 extdev/appapi.html#$ - +sphinx.application.TemplateBridge py:class 1 extdev/appapi.html#$ - +sphinx.application.TemplateBridge.init py:method 1 extdev/appapi.html#$ - +sphinx.application.TemplateBridge.newest_template_mtime py:method 1 extdev/appapi.html#$ - +sphinx.application.TemplateBridge.render py:method 1 extdev/appapi.html#$ - +sphinx.application.TemplateBridge.render_string py:method 1 extdev/appapi.html#$ - +sphinx.builders py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.Builder py:class 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.allow_parallel py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.build py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.build_all py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.build_specific py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.build_update py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.default_translator_class py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.epilog py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.events py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.finish py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.format py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.get_outdated_docs py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.get_relative_uri py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.get_target_uri py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.init py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.name py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.prepare_writing py:method 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.supported_data_uri_images py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.supported_image_types py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.supported_remote_images py:attribute 1 extdev/builderapi.html#$ - +sphinx.builders.Builder.write_doc py:method 1 extdev/builderapi.html#$ - +sphinx.builders.changes py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.changes.ChangesBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.changes.ChangesBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.changes.ChangesBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.changes.ChangesBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.dirhtml py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.dirhtml.DirectoryHTMLBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.dirhtml.DirectoryHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.dirhtml.DirectoryHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.dirhtml.DirectoryHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.dummy py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.dummy.DummyBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.dummy.DummyBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.dummy.DummyBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.epub3 py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.epub3.Epub3Builder py:class 1 usage/builders/index.html#$ - +sphinx.builders.epub3.Epub3Builder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.epub3.Epub3Builder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.epub3.Epub3Builder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.gettext py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.gettext.MessageCatalogBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.gettext.MessageCatalogBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.gettext.MessageCatalogBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.gettext.MessageCatalogBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.html py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.html.StandaloneHTMLBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.html.StandaloneHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.html.StandaloneHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.html.StandaloneHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.latex py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.latex.LaTeXBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.latex.LaTeXBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.latex.LaTeXBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.latex.LaTeXBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.linkcheck py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.linkcheck.CheckExternalLinksBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.linkcheck.CheckExternalLinksBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.linkcheck.CheckExternalLinksBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.linkcheck.CheckExternalLinksBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.manpage py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.manpage.ManualPageBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.manpage.ManualPageBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.manpage.ManualPageBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.manpage.ManualPageBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.singlehtml py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.singlehtml.SingleFileHTMLBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.singlehtml.SingleFileHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.singlehtml.SingleFileHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.singlehtml.SingleFileHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.texinfo py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.texinfo.TexinfoBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.texinfo.TexinfoBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.texinfo.TexinfoBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.texinfo.TexinfoBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.text py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.text.TextBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.text.TextBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.text.TextBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.text.TextBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.xml py:module 0 usage/builders/index.html#module-$ - +sphinx.builders.xml.PseudoXMLBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.xml.PseudoXMLBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.xml.PseudoXMLBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.xml.PseudoXMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.xml.XMLBuilder py:class 1 usage/builders/index.html#$ - +sphinx.builders.xml.XMLBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.xml.XMLBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinx.builders.xml.XMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinx.config.Config py:class 1 extdev/appapi.html#$ - +sphinx.directives py:module 0 extdev/domainapi.html#module-$ - +sphinx.directives.ObjectDescription py:class 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription._object_hierarchy_parts py:method 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription._toc_entry_name py:method 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.add_target_and_index py:method 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.after_content py:method 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.before_content py:method 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.final_argument_whitespace py:attribute 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.get_signatures py:method 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.handle_signature py:method 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.has_content py:attribute 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.option_spec py:attribute 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.optional_arguments py:attribute 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.required_arguments py:attribute 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.run py:method 1 extdev/domainapi.html#$ - +sphinx.directives.ObjectDescription.transform_content py:method 1 extdev/domainapi.html#$ - +sphinx.domains py:module 0 extdev/domainapi.html#module-$ - +sphinx.domains.Domain py:class 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.add_object_type py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.check_consistency py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.clear_doc py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.dangling_warnings py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.data py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.data_version py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.directive py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.directives py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.enumerable_nodes py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.get_enumerable_node_type py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.get_full_qualified_name py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.get_objects py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.get_type_name py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.indices py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.initial_data py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.label py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.merge_domaindata py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.name py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.object_types py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.process_doc py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.process_field_xref py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.resolve_any_xref py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.resolve_xref py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.role py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.roles py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.Domain.setup py:method 1 extdev/domainapi.html#$ - +sphinx.domains.Index py:class 1 extdev/domainapi.html#$ - +sphinx.domains.Index.generate py:method 1 extdev/domainapi.html#$ - +sphinx.domains.ObjType py:class 1 extdev/domainapi.html#$ - +sphinx.domains.python py:module 0 extdev/domainapi.html#module-$ - +sphinx.domains.python.PythonDomain py:class 1 extdev/domainapi.html#$ - +sphinx.domains.python.PythonDomain.modules py:attribute 1 extdev/domainapi.html#$ - +sphinx.domains.python.PythonDomain.note_module py:method 1 extdev/domainapi.html#$ - +sphinx.domains.python.PythonDomain.note_object py:method 1 extdev/domainapi.html#$ - +sphinx.domains.python.PythonDomain.objects py:attribute 1 extdev/domainapi.html#$ - +sphinx.environment py:module 0 extdev/envapi.html#module-$ - +sphinx.environment.BuildEnvironment py:class 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.app py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.config py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.doc2path py:method 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.docname py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.doctreedir py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.events py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.found_docs py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.metadata py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.new_serialno py:method 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.note_dependency py:method 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.note_reread py:method 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.project py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.relfn2path py:method 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.srcdir py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.BuildEnvironment.titles py:attribute 1 extdev/envapi.html#$ - +sphinx.environment.collectors py:module 0 extdev/collectorapi.html#module-$ - +sphinx.environment.collectors.EnvironmentCollector py:class 1 extdev/collectorapi.html#$ - +sphinx.environment.collectors.EnvironmentCollector.clear_doc py:method 1 extdev/collectorapi.html#$ - +sphinx.environment.collectors.EnvironmentCollector.get_outdated_docs py:method 1 extdev/collectorapi.html#$ - +sphinx.environment.collectors.EnvironmentCollector.get_updated_docs py:method 1 extdev/collectorapi.html#$ - +sphinx.environment.collectors.EnvironmentCollector.merge_other py:method 1 extdev/collectorapi.html#$ - +sphinx.environment.collectors.EnvironmentCollector.process_doc py:method 1 extdev/collectorapi.html#$ - +sphinx.errors py:module 0 extdev/appapi.html#module-$ - +sphinx.errors.ConfigError py:exception 1 extdev/appapi.html#$ - +sphinx.errors.ExtensionError py:exception 1 extdev/appapi.html#$ - +sphinx.errors.SphinxError py:exception 1 extdev/appapi.html#$ - +sphinx.errors.SphinxError.category py:attribute 1 extdev/appapi.html#$ - +sphinx.errors.ThemeError py:exception 1 extdev/appapi.html#$ - +sphinx.errors.VersionRequirementError py:exception 1 extdev/appapi.html#$ - +sphinx.events.EventManager py:class 1 extdev/utils.html#$ - +sphinx.events.EventManager.add py:method 1 extdev/utils.html#$ - +sphinx.events.EventManager.connect py:method 1 extdev/utils.html#$ - +sphinx.events.EventManager.disconnect py:method 1 extdev/utils.html#$ - +sphinx.events.EventManager.emit py:method 1 extdev/utils.html#$ - +sphinx.events.EventManager.emit_firstresult py:method 1 extdev/utils.html#$ - +sphinx.ext.autodoc py:module 0 usage/extensions/autodoc.html#module-$ - +sphinx.ext.autodoc.between py:function 1 usage/extensions/autodoc.html#$ - +sphinx.ext.autodoc.cut_lines py:function 1 usage/extensions/autodoc.html#$ - +sphinx.ext.autosectionlabel py:module 0 usage/extensions/autosectionlabel.html#module-$ - +sphinx.ext.autosummary py:module 0 usage/extensions/autosummary.html#module-$ - +sphinx.ext.coverage py:module 0 usage/extensions/coverage.html#module-$ - +sphinx.ext.coverage.CoverageBuilder py:class 1 usage/extensions/coverage.html#$ - +sphinx.ext.doctest py:module 0 usage/extensions/doctest.html#module-$ - +sphinx.ext.duration py:module 0 usage/extensions/duration.html#module-$ - +sphinx.ext.extlinks py:module 0 usage/extensions/extlinks.html#module-$ - +sphinx.ext.githubpages py:module 0 usage/extensions/githubpages.html#module-$ - +sphinx.ext.graphviz py:module 0 usage/extensions/graphviz.html#module-$ - +sphinx.ext.ifconfig py:module 0 usage/extensions/ifconfig.html#module-$ - +sphinx.ext.imgconverter py:module 0 usage/extensions/imgconverter.html#module-$ - +sphinx.ext.imgmath py:module 0 usage/extensions/math.html#module-$ - +sphinx.ext.inheritance_diagram py:module 0 usage/extensions/inheritance.html#module-$ - +sphinx.ext.intersphinx py:module 0 usage/extensions/intersphinx.html#module-$ - +sphinx.ext.jsmath py:module 0 usage/extensions/math.html#module-$ - +sphinx.ext.linkcode py:module 0 usage/extensions/linkcode.html#module-$ - +sphinx.ext.mathbase py:module 0 usage/extensions/math.html#module-$ - +sphinx.ext.mathjax py:module 0 usage/extensions/math.html#module-$ - +sphinx.ext.napoleon py:module 0 usage/extensions/napoleon.html#module-$ - +sphinx.ext.todo py:module 0 usage/extensions/todo.html#module-$ - +sphinx.ext.viewcode py:module 0 usage/extensions/viewcode.html#module-$ - +sphinx.locale._ py:function 1 extdev/i18n.html#$ - +sphinx.locale.__ py:function 1 extdev/i18n.html#$ - +sphinx.locale.get_translation py:function 1 extdev/i18n.html#$ - +sphinx.locale.init py:function 1 extdev/i18n.html#$ - +sphinx.locale.init_console py:function 1 extdev/i18n.html#$ - +sphinx.parsers py:module 0 extdev/parserapi.html#module-$ - +sphinx.parsers.Parser py:class 1 extdev/parserapi.html#$ - +sphinx.parsers.Parser.config py:attribute 1 extdev/parserapi.html#$ - +sphinx.parsers.Parser.env py:attribute 1 extdev/parserapi.html#$ - +sphinx.parsers.Parser.set_application py:method 1 extdev/parserapi.html#$ - +sphinx.project.Project py:class 1 extdev/projectapi.html#$ - +sphinx.project.Project.discover py:method 1 extdev/projectapi.html#$ - +sphinx.project.Project.doc2path py:method 1 extdev/projectapi.html#$ - +sphinx.project.Project.docnames py:attribute 1 extdev/projectapi.html#$ - +sphinx.project.Project.path2doc py:method 1 extdev/projectapi.html#$ - +sphinx.project.Project.restore py:method 1 extdev/projectapi.html#$ - +sphinx.project.Project.source_suffix py:attribute 1 extdev/projectapi.html#$ - +sphinx.project.Project.srcdir py:attribute 1 extdev/projectapi.html#$ - +sphinx.transforms.SphinxTransform py:class 1 extdev/utils.html#$ - +sphinx.transforms.SphinxTransform.app py:property 1 extdev/utils.html#$ - +sphinx.transforms.SphinxTransform.config py:property 1 extdev/utils.html#$ - +sphinx.transforms.SphinxTransform.env py:property 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.SphinxPostTransform py:class 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.SphinxPostTransform.apply py:method 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.SphinxPostTransform.is_supported py:method 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.SphinxPostTransform.run py:method 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.images.ImageConverter py:class 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.images.ImageConverter.available py:attribute 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.images.ImageConverter.conversion_rules py:attribute 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.images.ImageConverter.convert py:method 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.images.ImageConverter.default_priority py:attribute 1 extdev/utils.html#$ - +sphinx.transforms.post_transforms.images.ImageConverter.is_available py:method 1 extdev/utils.html#$ - +sphinx.util.docutils.ReferenceRole py:class 1 extdev/utils.html#$ - +sphinx.util.docutils.ReferenceRole.disabled py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.ReferenceRole.has_explicit_title py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.ReferenceRole.target py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.ReferenceRole.title py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxDirective py:class 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxDirective.config py:property 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxDirective.env py:property 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxDirective.get_location py:method 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxDirective.get_source_info py:method 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxDirective.set_source_info py:method 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole py:class 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.config py:property 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.content py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.env py:property 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.get_location py:method 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.inliner py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.lineno py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.name py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.options py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.rawtext py:attribute 1 extdev/utils.html#$ - +sphinx.util.docutils.SphinxRole.text py:attribute 1 extdev/utils.html#$ - +sphinx.util.logging.SphinxLoggerAdapter py:class 1 extdev/logging.html#$ - +sphinx.util.logging.SphinxLoggerAdapter.critical py:method 1 extdev/logging.html#$ - +sphinx.util.logging.SphinxLoggerAdapter.debug py:method 1 extdev/logging.html#$ - +sphinx.util.logging.SphinxLoggerAdapter.error py:method 1 extdev/logging.html#$ - +sphinx.util.logging.SphinxLoggerAdapter.info py:method 1 extdev/logging.html#$ - +sphinx.util.logging.SphinxLoggerAdapter.log py:method 1 extdev/logging.html#$ - +sphinx.util.logging.SphinxLoggerAdapter.verbose py:method 1 extdev/logging.html#$ - +sphinx.util.logging.SphinxLoggerAdapter.warning py:method 1 extdev/logging.html#$ - +sphinx.util.logging.getLogger py:function 1 extdev/logging.html#$ - +sphinx.util.logging.pending_logging py:function 1 extdev/logging.html#$ - +sphinx.util.logging.pending_warnings py:function 1 extdev/logging.html#$ - +sphinx.util.logging.prefixed_warnings py:function 1 extdev/logging.html#$ - +sphinx.version_info py:data 1 extdev/appapi.html#$ - +sphinx_version py:data 1 templating.html#$ - +sphinx_version_tuple py:data 1 templating.html#$ - +sphinxcontrib.applehelp py:module 0 usage/builders/index.html#module-$ - +sphinxcontrib.applehelp.AppleHelpBuilder py:class 1 usage/builders/index.html#$ - +sphinxcontrib.applehelp.AppleHelpBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.applehelp.AppleHelpBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.applehelp.AppleHelpBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.devhelp py:module 0 usage/builders/index.html#module-$ - +sphinxcontrib.devhelp.DevhelpBuilder py:class 1 usage/builders/index.html#$ - +sphinxcontrib.devhelp.DevhelpBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.devhelp.DevhelpBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.devhelp.DevhelpBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.htmlhelp py:module 0 usage/builders/index.html#module-$ - +sphinxcontrib.htmlhelp.HTMLHelpBuilder py:class 1 usage/builders/index.html#$ - +sphinxcontrib.htmlhelp.HTMLHelpBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.htmlhelp.HTMLHelpBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.htmlhelp.HTMLHelpBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.qthelp py:module 0 usage/builders/index.html#module-$ - +sphinxcontrib.qthelp.QtHelpBuilder py:class 1 usage/builders/index.html#$ - +sphinxcontrib.qthelp.QtHelpBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.qthelp.QtHelpBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.qthelp.QtHelpBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.JSONHTMLBuilder py:class 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.JSONHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.JSONHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.JSONHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.PickleHTMLBuilder py:class 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.PickleHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.PickleHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.PickleHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.SerializingHTMLBuilder py:class 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.SerializingHTMLBuilder.globalcontext_filename py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.SerializingHTMLBuilder.implementation py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.SerializingHTMLBuilder.out_suffix py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.serializinghtml.SerializingHTMLBuilder.searchindex_filename py:attribute 1 usage/builders/index.html#$ - +sphinxcontrib.websupport.WebSupport py:class 1 usage/advanced/websupport/api.html#$ - +sphinxcontrib.websupport.WebSupport.add_comment py:method 1 usage/advanced/websupport/api.html#$ - +sphinxcontrib.websupport.WebSupport.build py:method 1 usage/advanced/websupport/api.html#$ - +sphinxcontrib.websupport.WebSupport.get_data py:method 1 usage/advanced/websupport/api.html#$ - +sphinxcontrib.websupport.WebSupport.get_document py:method 1 usage/advanced/websupport/api.html#$ - +sphinxcontrib.websupport.WebSupport.get_search_results py:method 1 usage/advanced/websupport/api.html#$ - +sphinxcontrib.websupport.WebSupport.process_vote py:method 1 usage/advanced/websupport/api.html#$ - +sphinxcontrib.websupport.search.BaseSearch py:class 1 usage/advanced/websupport/searchadapters.html#$ - +sphinxcontrib.websupport.search.BaseSearch.add_document py:method 1 usage/advanced/websupport/searchadapters.html#$ - +sphinxcontrib.websupport.search.BaseSearch.extract_context py:method 1 usage/advanced/websupport/searchadapters.html#$ - +sphinxcontrib.websupport.search.BaseSearch.feed py:method 1 usage/advanced/websupport/searchadapters.html#$ - +sphinxcontrib.websupport.search.BaseSearch.finish_indexing py:method 1 usage/advanced/websupport/searchadapters.html#$ - +sphinxcontrib.websupport.search.BaseSearch.handle_query py:method 1 usage/advanced/websupport/searchadapters.html#$ - +sphinxcontrib.websupport.search.BaseSearch.init_indexing py:method 1 usage/advanced/websupport/searchadapters.html#$ - +sphinxcontrib.websupport.search.BaseSearch.query py:method 1 usage/advanced/websupport/searchadapters.html#$ - +sphinxcontrib.websupport.storage.StorageBackend py:class 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.accept_comment py:method 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.add_comment py:method 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.add_node py:method 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.delete_comment py:method 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.get_data py:method 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.post_build py:method 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.pre_build py:method 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.process_vote py:method 1 usage/advanced/websupport/storagebackends.html#$ - +sphinxcontrib.websupport.storage.StorageBackend.update_username py:method 1 usage/advanced/websupport/storagebackends.html#$ - +style py:data 1 templating.html#$ - +styles py:data 1 templating.html#$ - +title py:data 1 templating.html#$ - +toc py:data 1 templating.html#$ - +toctree py:data 1 templating.html#$ - +underline py:data 1 usage/extensions/autosummary.html#$ - +use_opensearch py:data 1 templating.html#$ - +version py:data 1 templating.html#$ - +warning py:function 1 templating.html#$ - +abbr rst:role 1 usage/restructuredtext/roles.html#role-$ - +any rst:role 1 usage/restructuredtext/roles.html#role-$ - +autoattribute rst:directive 1 usage/extensions/autodoc.html#directive-$ - +autoclass rst:directive 1 usage/extensions/autodoc.html#directive-$ - +autodata rst:directive 1 usage/extensions/autodoc.html#directive-$ - +autodecorator rst:directive 1 usage/extensions/autodoc.html#directive-$ - +autoexception rst:directive 1 usage/extensions/autodoc.html#directive-$ - +autofunction rst:directive 1 usage/extensions/autodoc.html#directive-$ - +automethod rst:directive 1 usage/extensions/autodoc.html#directive-$ - +automodule rst:directive 1 usage/extensions/autodoc.html#directive-$ - +automodule:members rst:directive:option 1 usage/extensions/autodoc.html#directive-option-automodule-members - +automodule:private-members rst:directive:option 1 usage/extensions/autodoc.html#directive-option-automodule-private-members - +automodule:special-members rst:directive:option 1 usage/extensions/autodoc.html#directive-option-automodule-special-members - +automodule:undoc-members rst:directive:option 1 usage/extensions/autodoc.html#directive-option-automodule-undoc-members - +autoproperty rst:directive 1 usage/extensions/autodoc.html#directive-$ - +autosummary rst:directive 1 usage/extensions/autosummary.html#directive-$ - +c:alias rst:directive 1 usage/restructuredtext/domains.html#directive-c-alias - +c:alias:maxdepth rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-c-alias-maxdepth - +c:alias:noroot rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-c-alias-noroot - +c:data rst:role 1 usage/restructuredtext/domains.html#role-c-data - +c:enum rst:directive 1 usage/restructuredtext/domains.html#directive-c-enum - +c:enum rst:role 1 usage/restructuredtext/domains.html#role-c-enum - +c:enumerator rst:directive 1 usage/restructuredtext/domains.html#directive-c-enumerator - +c:enumerator rst:role 1 usage/restructuredtext/domains.html#role-c-enumerator - +c:expr rst:role 1 usage/restructuredtext/domains.html#role-c-expr - +c:func rst:role 1 usage/restructuredtext/domains.html#role-c-func - +c:function rst:directive 1 usage/restructuredtext/domains.html#directive-c-function - +c:macro rst:directive 1 usage/restructuredtext/domains.html#directive-c-macro - +c:macro rst:role 1 usage/restructuredtext/domains.html#role-c-macro - +c:member rst:directive 1 usage/restructuredtext/domains.html#directive-c-member - +c:member rst:role 1 usage/restructuredtext/domains.html#role-c-member - +c:namespace rst:directive 1 usage/restructuredtext/domains.html#directive-c-namespace - +c:namespace-pop rst:directive 1 usage/restructuredtext/domains.html#directive-c-namespace-pop - +c:namespace-push rst:directive 1 usage/restructuredtext/domains.html#directive-c-namespace-push - +c:struct rst:directive 1 usage/restructuredtext/domains.html#directive-c-struct - +c:struct rst:role 1 usage/restructuredtext/domains.html#role-c-struct - +c:texpr rst:role 1 usage/restructuredtext/domains.html#role-c-texpr - +c:type rst:directive 1 usage/restructuredtext/domains.html#directive-c-type - +c:type rst:role 1 usage/restructuredtext/domains.html#role-c-type - +c:union rst:directive 1 usage/restructuredtext/domains.html#directive-c-union - +c:union rst:role 1 usage/restructuredtext/domains.html#role-c-union - +c:var rst:directive 1 usage/restructuredtext/domains.html#directive-c-var - +c:var rst:role 1 usage/restructuredtext/domains.html#role-c-var - +centered rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +code rst:role 1 usage/restructuredtext/roles.html#role-$ - +code-block rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +code-block:caption rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-caption - +code-block:class rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-class - +code-block:dedent rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-dedent - +code-block:emphasize-lines rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-emphasize-lines - +code-block:force rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-force - +code-block:lineno-start rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-lineno-start - +code-block:linenos rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-linenos - +code-block:name rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-name - +codeauthor rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +command rst:role 1 usage/restructuredtext/roles.html#role-$ - +cpp:alias rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-alias - +cpp:alias:maxdepth rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-cpp-alias-maxdepth - +cpp:alias:noroot rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-cpp-alias-noroot - +cpp:any rst:role 1 usage/restructuredtext/domains.html#role-cpp-any - +cpp:class rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-class - +cpp:class rst:role 1 usage/restructuredtext/domains.html#role-cpp-class - +cpp:concept rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-concept - +cpp:concept rst:role 1 usage/restructuredtext/domains.html#role-cpp-concept - +cpp:enum rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-enum - +cpp:enum rst:role 1 usage/restructuredtext/domains.html#role-cpp-enum - +cpp:enum-class rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-enum-class - +cpp:enum-struct rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-enum-struct - +cpp:enumerator rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-enumerator - +cpp:enumerator rst:role 1 usage/restructuredtext/domains.html#role-cpp-enumerator - +cpp:expr rst:role 1 usage/restructuredtext/domains.html#role-cpp-expr - +cpp:func rst:role 1 usage/restructuredtext/domains.html#role-cpp-func - +cpp:function rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-function - +cpp:member rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-member - +cpp:member rst:role 1 usage/restructuredtext/domains.html#role-cpp-member - +cpp:namespace rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-namespace - +cpp:namespace-pop rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-namespace-pop - +cpp:namespace-push rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-namespace-push - +cpp:struct rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-struct - +cpp:struct rst:role 1 usage/restructuredtext/domains.html#role-cpp-struct - +cpp:texpr rst:role 1 usage/restructuredtext/domains.html#role-cpp-texpr - +cpp:type rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-type - +cpp:type rst:role 1 usage/restructuredtext/domains.html#role-cpp-type - +cpp:union rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-union - +cpp:var rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-var - +cpp:var rst:role 1 usage/restructuredtext/domains.html#role-cpp-var - +default-domain rst:directive 1 usage/restructuredtext/domains.html#directive-$ - +deprecated rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +describe rst:directive 1 usage/restructuredtext/domains.html#directive-$ - +dfn rst:role 1 usage/restructuredtext/roles.html#role-$ - +digraph rst:directive 1 usage/extensions/graphviz.html#directive-$ - +digraph:align rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-align - +digraph:alt rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-alt - +digraph:caption rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-caption - +digraph:class rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-class - +digraph:layout rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-layout - +digraph:name rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-name - +doc rst:role 1 usage/restructuredtext/roles.html#role-$ - +doctest rst:directive 1 usage/extensions/doctest.html#directive-$ - +download rst:role 1 usage/restructuredtext/roles.html#role-$ - +envvar rst:directive 1 usage/restructuredtext/domains.html#directive-$ - +envvar rst:role 1 usage/restructuredtext/roles.html#role-$ - +eq rst:role 1 usage/restructuredtext/roles.html#role-$ - +external rst:role 1 usage/extensions/intersphinx.html#role-$ - +file rst:role 1 usage/restructuredtext/roles.html#role-$ - +glossary rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +graph rst:directive 1 usage/extensions/graphviz.html#directive-$ - +graph:align rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-align - +graph:alt rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-alt - +graph:caption rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-caption - +graph:class rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-class - +graph:layout rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-layout - +graph:name rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-name - +graphviz rst:directive 1 usage/extensions/graphviz.html#directive-$ - +graphviz:align rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-align - +graphviz:alt rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-alt - +graphviz:caption rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-caption - +graphviz:class rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-class - +graphviz:layout rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-layout - +graphviz:name rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-name - +guilabel rst:role 1 usage/restructuredtext/roles.html#role-$ - +highlight rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +highlight:force rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-highlight-force - +highlight:linenothreshold rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-highlight-linenothreshold - +hlist rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +ifconfig rst:directive 1 usage/extensions/ifconfig.html#directive-$ - +index rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +index rst:role 1 usage/restructuredtext/directives.html#role-$ - +index:name rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-index-name - +inheritance-diagram rst:directive 1 usage/extensions/inheritance.html#directive-$ - +js:attr rst:role 1 usage/restructuredtext/domains.html#role-js-attr - +js:attribute rst:directive 1 usage/restructuredtext/domains.html#directive-js-attribute - +js:class rst:directive 1 usage/restructuredtext/domains.html#directive-js-class - +js:class rst:role 1 usage/restructuredtext/domains.html#role-js-class - +js:data rst:directive 1 usage/restructuredtext/domains.html#directive-js-data - +js:data rst:role 1 usage/restructuredtext/domains.html#role-js-data - +js:func rst:role 1 usage/restructuredtext/domains.html#role-js-func - +js:function rst:directive 1 usage/restructuredtext/domains.html#directive-js-function - +js:meth rst:role 1 usage/restructuredtext/domains.html#role-js-meth - +js:method rst:directive 1 usage/restructuredtext/domains.html#directive-js-method - +js:mod rst:role 1 usage/restructuredtext/domains.html#role-js-mod - +js:module rst:directive 1 usage/restructuredtext/domains.html#directive-js-module - +kbd rst:role 1 usage/restructuredtext/roles.html#role-$ - +keyword rst:role 1 usage/restructuredtext/roles.html#role-$ - +literalinclude rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +mailheader rst:role 1 usage/restructuredtext/roles.html#role-$ - +makevar rst:role 1 usage/restructuredtext/roles.html#role-$ - +manpage rst:role 1 usage/restructuredtext/roles.html#role-$ - +math rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +math rst:role 1 usage/restructuredtext/roles.html#role-$ - +math:numref rst:role 1 usage/restructuredtext/domains.html#role-math-numref - +menuselection rst:role 1 usage/restructuredtext/roles.html#role-$ - +mimetype rst:role 1 usage/restructuredtext/roles.html#role-$ - +newsgroup rst:role 1 usage/restructuredtext/roles.html#role-$ - +note rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +numref rst:role 1 usage/restructuredtext/roles.html#role-$ - +object rst:directive 1 usage/restructuredtext/domains.html#directive-$ - +only rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +option rst:directive 1 usage/restructuredtext/domains.html#directive-$ - +option rst:role 1 usage/restructuredtext/roles.html#role-$ - +pep rst:role 1 usage/restructuredtext/roles.html#role-$ - +productionlist rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +program rst:directive 1 usage/restructuredtext/domains.html#directive-$ - +program rst:role 1 usage/restructuredtext/roles.html#role-$ - +py:attr rst:role 1 usage/restructuredtext/domains.html#role-py-attr - +py:attribute rst:directive 1 usage/restructuredtext/domains.html#directive-py-attribute - +py:attribute:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-attribute-canonical - +py:attribute:type rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-attribute-type - +py:attribute:value rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-attribute-value - +py:class rst:directive 1 usage/restructuredtext/domains.html#directive-py-class - +py:class rst:role 1 usage/restructuredtext/domains.html#role-py-class - +py:class:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-class-canonical - +py:class:final rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-class-final - +py:classmethod rst:directive 1 usage/restructuredtext/domains.html#directive-py-classmethod - +py:const rst:role 1 usage/restructuredtext/domains.html#role-py-const - +py:currentmodule rst:directive 1 usage/restructuredtext/domains.html#directive-py-currentmodule - +py:data rst:directive 1 usage/restructuredtext/domains.html#directive-py-data - +py:data rst:role 1 usage/restructuredtext/domains.html#role-py-data - +py:data:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-data-canonical - +py:data:type rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-data-type - +py:data:value rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-data-value - +py:decorator rst:directive 1 usage/restructuredtext/domains.html#directive-py-decorator - +py:decoratormethod rst:directive 1 usage/restructuredtext/domains.html#directive-py-decoratormethod - +py:exc rst:role 1 usage/restructuredtext/domains.html#role-py-exc - +py:exception rst:directive 1 usage/restructuredtext/domains.html#directive-py-exception - +py:exception:final rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-exception-final - +py:func rst:role 1 usage/restructuredtext/domains.html#role-py-func - +py:function rst:directive 1 usage/restructuredtext/domains.html#directive-py-function - +py:function:async rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-function-async - +py:function:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-function-canonical - +py:meth rst:role 1 usage/restructuredtext/domains.html#role-py-meth - +py:method rst:directive 1 usage/restructuredtext/domains.html#directive-py-method - +py:method:abstractmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-abstractmethod - +py:method:async rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-async - +py:method:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-canonical - +py:method:classmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-classmethod - +py:method:final rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-final - +py:method:staticmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-staticmethod - +py:mod rst:role 1 usage/restructuredtext/domains.html#role-py-mod - +py:module rst:directive 1 usage/restructuredtext/domains.html#directive-py-module - +py:module:deprecated rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-module-deprecated - +py:module:platform rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-module-platform - +py:module:synopsis rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-module-synopsis - +py:obj rst:role 1 usage/restructuredtext/domains.html#role-py-obj - +py:property rst:directive 1 usage/restructuredtext/domains.html#directive-py-property - +py:property:abstractmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-property-abstractmethod - +py:property:classmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-property-classmethod - +py:property:type rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-property-type - +py:staticmethod rst:directive 1 usage/restructuredtext/domains.html#directive-py-staticmethod - +ref rst:role 1 usage/restructuredtext/roles.html#role-$ - +regexp rst:role 1 usage/restructuredtext/roles.html#role-$ - +rfc rst:role 1 usage/restructuredtext/roles.html#role-$ - +rst:dir rst:role 1 usage/restructuredtext/domains.html#role-rst-dir - +rst:directive rst:directive 1 usage/restructuredtext/domains.html#directive-rst-directive - +rst:directive:option rst:directive 1 usage/restructuredtext/domains.html#directive-rst-directive-option - +rst:directive:option:type rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-rst-directive-option-type - +rst:role rst:directive 1 usage/restructuredtext/domains.html#directive-rst-role - +rst:role rst:role 1 usage/restructuredtext/domains.html#role-rst-role - +rubric rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +samp rst:role 1 usage/restructuredtext/roles.html#role-$ - +sectionauthor rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +seealso rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +tabularcolumns rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +term rst:role 1 usage/restructuredtext/roles.html#role-$ - +testcleanup rst:directive 1 usage/extensions/doctest.html#directive-$ - +testcode rst:directive 1 usage/extensions/doctest.html#directive-$ - +testoutput rst:directive 1 usage/extensions/doctest.html#directive-$ - +testsetup rst:directive 1 usage/extensions/doctest.html#directive-$ - +toctree rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +todo rst:directive 1 usage/extensions/todo.html#directive-$ - +todolist rst:directive 1 usage/extensions/todo.html#directive-$ - +token rst:role 1 usage/restructuredtext/roles.html#role-$ - +versionadded rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +versionchanged rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +warning rst:directive 1 usage/restructuredtext/directives.html#directive-$ - +RemoveInSphinxXXXWarning std:term -1 glossary.html#term-$ - +SPHINX_APIDOC_OPTIONS std:envvar 1 man/sphinx-apidoc.html#envvar-$ - +add_function_parentheses std:confval 1 usage/configuration.html#confval-$ - +add_module_names std:confval 1 usage/configuration.html#confval-$ - +additionalcss std:label -1 latex.html#$ Additional CSS-like 'sphinxsetup' keys +all-files std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +any-role std:label -1 usage/restructuredtext/roles.html#$ Cross-referencing anything +applehelp-options std:label -1 usage/configuration.html#$ Options for Apple Help output +applehelp_bundle_id std:confval 1 usage/configuration.html#confval-$ - +applehelp_bundle_name std:confval 1 usage/configuration.html#confval-$ - +applehelp_bundle_version std:confval 1 usage/configuration.html#confval-$ - +applehelp_codesign_flags std:confval 1 usage/configuration.html#confval-$ - +applehelp_codesign_identity std:confval 1 usage/configuration.html#confval-$ - +applehelp_codesign_path std:confval 1 usage/configuration.html#confval-$ - +applehelp_dev_region std:confval 1 usage/configuration.html#confval-$ - +applehelp_disable_external_tools std:confval 1 usage/configuration.html#confval-$ - +applehelp_icon std:confval 1 usage/configuration.html#confval-$ - +applehelp_index_anchors std:confval 1 usage/configuration.html#confval-$ - +applehelp_indexer_path std:confval 1 usage/configuration.html#confval-$ - +applehelp_kb_product std:confval 1 usage/configuration.html#confval-$ - +applehelp_kb_url std:confval 1 usage/configuration.html#confval-$ - +applehelp_locale std:confval 1 usage/configuration.html#confval-$ - +applehelp_min_term_length std:confval 1 usage/configuration.html#confval-$ - +applehelp_remote_url std:confval 1 usage/configuration.html#confval-$ - +applehelp_stopwords std:confval 1 usage/configuration.html#confval-$ - +applehelp_title std:confval 1 usage/configuration.html#confval-$ - +author std:confval 1 usage/configuration.html#confval-$ - +authors std:label -1 internals/authors.html#$ Sphinx authors +autoclass_content std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc-before-process-signature std:event 1 usage/extensions/autodoc.html#event-$ - +autodoc-process-bases std:event 1 usage/extensions/autodoc.html#event-$ - +autodoc-process-docstring std:event 1 usage/extensions/autodoc.html#event-$ - +autodoc-process-signature std:event 1 usage/extensions/autodoc.html#event-$ - +autodoc-skip-member std:event 1 usage/extensions/autodoc.html#event-$ - +autodoc_class_signature std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_default_flags std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_default_options std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_docstring_signature std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_ext_tutorial std:label -1 development/tutorials/autodoc_ext.html#autodoc-ext-tutorial Developing autodoc extension for IntEnum +autodoc_inherit_docstrings std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_member_order std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_mock_imports std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_preserve_defaults std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_type_aliases std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_typehints std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_typehints_description_target std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_typehints_format std:confval 1 usage/extensions/autodoc.html#confval-$ - +autodoc_warningiserror std:confval 1 usage/extensions/autodoc.html#confval-$ - +autosectionlabel_maxdepth std:confval 1 usage/extensions/autosectionlabel.html#confval-$ - +autosectionlabel_prefix_document std:confval 1 usage/extensions/autosectionlabel.html#confval-$ - +autosummary-customizing-templates std:label -1 usage/extensions/autosummary.html#$ Customizing templates +autosummary_context std:confval 1 usage/extensions/autosummary.html#confval-$ - +autosummary_filename_map std:confval 1 usage/extensions/autosummary.html#confval-$ - +autosummary_generate std:confval 1 usage/extensions/autosummary.html#confval-$ - +autosummary_generate_overwrite std:confval 1 usage/extensions/autosummary.html#confval-$ - +autosummary_ignore_module_all std:confval 1 usage/extensions/autosummary.html#confval-$ - +autosummary_imported_members std:confval 1 usage/extensions/autosummary.html#confval-$ - +autosummary_mock_imports std:confval 1 usage/extensions/autosummary.html#confval-$ - +basic-domain-markup std:label -1 usage/restructuredtext/domains.html#$ Basic Markup +build-config std:label -1 usage/configuration.html#$ Configuration +build-dir std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +build-finished std:event 1 extdev/appapi.html#event-$ - +build-phases std:label -1 extdev/index.html#$ Build Phases +builder std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +builder std:term -1 glossary.html#term-$ - +builder-inited std:event 1 extdev/appapi.html#event-$ - +builders std:label -1 usage/builders/index.html#$ Builders +builtin-extensions std:label -1 usage/extensions/index.html#$ Built-in extensions +builtin-themes std:label -1 usage/theming.html#$ Builtin themes +c-config std:label -1 usage/configuration.html#$ Options for the C domain +c-domain std:label -1 usage/restructuredtext/domains.html#$ The C Domain +c-roles std:label -1 usage/restructuredtext/domains.html#$ Cross-referencing C constructs +c_extra_keywords std:confval 1 usage/configuration.html#confval-$ - +c_id_attributes std:confval 1 usage/configuration.html#confval-$ - +c_paren_attributes std:confval 1 usage/configuration.html#confval-$ - +changes std:doc -1 changes.html Changelog +changes std:label -1 changes.html#$ Changelog +code-examples std:label -1 usage/restructuredtext/directives.html#$ Showing code examples +code_of_conduct std:label -1 internals/code-of-conduct.html#code-of-conduct Sphinx Code of Conduct +collector-api std:label -1 extdev/collectorapi.html#$ Environment Collector API +conf-tags std:label -1 usage/configuration.html#$ - +config-dir std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +config-inited std:event 1 extdev/appapi.html#event-$ - +configuration directory std:term -1 glossary.html#term-configuration-directory - +contribute-get-started std:label -1 internals/contributing.html#$ Getting started +copyright std:confval 1 usage/configuration.html#confval-$ - +copyright std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +coverage_c_path std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_c_regexes std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_ignore_c_items std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_ignore_classes std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_ignore_functions std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_ignore_modules std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_ignore_pyobjects std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_show_missing_items std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_skip_undoc_in_source std:confval 1 usage/extensions/coverage.html#confval-$ - +coverage_write_headline std:confval 1 usage/extensions/coverage.html#confval-$ - +cpp-config std:label -1 usage/configuration.html#$ Options for the C++ domain +cpp-domain std:label -1 usage/restructuredtext/domains.html#$ The C++ Domain +cpp-roles std:label -1 usage/restructuredtext/domains.html#$ Cross-referencing +cpp_id_attributes std:confval 1 usage/configuration.html#confval-$ - +cpp_index_common_prefix std:confval 1 usage/configuration.html#confval-$ - +cpp_paren_attributes std:confval 1 usage/configuration.html#confval-$ - +default-substitutions std:label -1 usage/restructuredtext/roles.html#$ Substitutions +default_role std:confval 1 usage/configuration.html#confval-$ - +deprecation-policy std:label -1 internals/release-process.html#$ Deprecation policy +dev-deprecated-apis std:label -1 extdev/deprecated.html#$ Deprecated APIs +dev-extensions std:label -1 extdev/index.html#$ Developing extensions for Sphinx +development/builders std:doc -1 development/builders.html Configuring builders +development/index std:doc -1 development/index.html Extending Sphinx +development/overview std:doc -1 development/overview.html Developing extensions overview +development/theming std:doc -1 development/theming.html HTML theme development +development/tutorials/autodoc_ext std:doc -1 development/tutorials/autodoc_ext.html Developing autodoc extension for IntEnum +development/tutorials/examples/README std:doc -1 development/tutorials/examples/README.html Tutorial examples +development/tutorials/helloworld std:doc -1 development/tutorials/helloworld.html Developing a “Hello world” extension +development/tutorials/index std:doc -1 development/tutorials/index.html Extension tutorials +development/tutorials/recipe std:doc -1 development/tutorials/recipe.html Developing a “recipe” extension +development/tutorials/todo std:doc -1 development/tutorials/todo.html Developing a “TODO” extension +dic_enc option std:label -1 usage/configuration.html#dic-enc-option - +dict option std:label -1 usage/configuration.html#dict-option - +directive std:term -1 glossary.html#term-$ - +distribute-your-theme std:label -1 development/theming.html#$ Distribute your theme as a Python package +doctest_default_flags std:confval 1 usage/extensions/doctest.html#confval-$ - +doctest_global_cleanup std:confval 1 usage/extensions/doctest.html#confval-$ - +doctest_global_setup std:confval 1 usage/extensions/doctest.html#confval-$ - +doctest_path std:confval 1 usage/extensions/doctest.html#confval-$ - +doctest_test_doctest_blocks std:confval 1 usage/extensions/doctest.html#confval-$ - +doctree-read std:event 1 extdev/appapi.html#event-$ - +doctree-resolved std:event 1 extdev/appapi.html#event-$ - +document name std:term -1 glossary.html#term-document-name - +domain std:term -1 glossary.html#term-$ - +domain-api std:label -1 extdev/domainapi.html#$ Domain API +domains-std std:label -1 usage/restructuredtext/domains.html#$ The Standard Domain +env-before-read-docs std:event 1 extdev/appapi.html#event-$ - +env-check-consistency std:event 1 extdev/appapi.html#event-$ - +env-get-outdated std:event 1 extdev/appapi.html#event-$ - +env-merge-info std:event 1 extdev/appapi.html#event-$ - +env-purge-doc std:event 1 extdev/appapi.html#event-$ - +env-updated std:event 1 extdev/appapi.html#event-$ - +environment std:term -1 glossary.html#term-$ - +epub-faq std:label -1 faq.html#$ Epub info +epub-options std:label -1 usage/configuration.html#$ Options for epub output +epub_author std:confval 1 usage/configuration.html#confval-$ - +epub_basename std:confval 1 usage/configuration.html#confval-$ - +epub_contributor std:confval 1 usage/configuration.html#confval-$ - +epub_copyright std:confval 1 usage/configuration.html#confval-$ - +epub_cover std:confval 1 usage/configuration.html#confval-$ - +epub_css_files std:confval 1 usage/configuration.html#confval-$ - +epub_description std:confval 1 usage/configuration.html#confval-$ - +epub_exclude_files std:confval 1 usage/configuration.html#confval-$ - +epub_fix_images std:confval 1 usage/configuration.html#confval-$ - +epub_guide std:confval 1 usage/configuration.html#confval-$ - +epub_identifier std:confval 1 usage/configuration.html#confval-$ - +epub_language std:confval 1 usage/configuration.html#confval-$ - +epub_max_image_width std:confval 1 usage/configuration.html#confval-$ - +epub_post_files std:confval 1 usage/configuration.html#confval-$ - +epub_pre_files std:confval 1 usage/configuration.html#confval-$ - +epub_publisher std:confval 1 usage/configuration.html#confval-$ - +epub_scheme std:confval 1 usage/configuration.html#confval-$ - +epub_show_urls std:confval 1 usage/configuration.html#confval-$ - +epub_theme std:confval 1 usage/configuration.html#confval-$ - +epub_theme_options std:confval 1 usage/configuration.html#confval-$ - +epub_title std:confval 1 usage/configuration.html#confval-$ - +epub_tocdepth std:confval 1 usage/configuration.html#confval-$ - +epub_tocdup std:confval 1 usage/configuration.html#confval-$ - +epub_tocscope std:confval 1 usage/configuration.html#confval-$ - +epub_uid std:confval 1 usage/configuration.html#confval-$ - +epub_use_index std:confval 1 usage/configuration.html#confval-$ - +epub_writing_mode std:confval 1 usage/configuration.html#confval-$ - +events std:label -1 extdev/appapi.html#$ Sphinx core events +example_google std:label -1 usage/extensions/example_google.html#example-google Example Google Style Python Docstrings +example_numpy std:label -1 usage/extensions/example_numpy.html#example-numpy Example NumPy Style Python Docstrings +examples std:doc -1 examples.html Projects using Sphinx +examples std:label -1 examples.html#$ Projects using Sphinx +exceptions std:label -1 extdev/appapi.html#$ Exceptions +exclude_patterns std:confval 1 usage/configuration.html#confval-$ - +ext-i18n std:label -1 extdev/i18n.html#$ Extension internationalization (i18n) and localization (l10n) using i18n API +ext-metadata std:label -1 extdev/index.html#$ Extension metadata +extdev/appapi std:doc -1 extdev/appapi.html Application API +extdev/builderapi std:doc -1 extdev/builderapi.html Builder API +extdev/collectorapi std:doc -1 extdev/collectorapi.html Environment Collector API +extdev/deprecated std:doc -1 extdev/deprecated.html Deprecated APIs +extdev/domainapi std:doc -1 extdev/domainapi.html Domain API +extdev/envapi std:doc -1 extdev/envapi.html Build environment API +extdev/i18n std:doc -1 extdev/i18n.html i18n API +extdev/index std:doc -1 extdev/index.html Developing extensions for Sphinx +extdev/logging std:doc -1 extdev/logging.html Logging API +extdev/markupapi std:doc -1 extdev/markupapi.html Docutils markup API +extdev/nodes std:doc -1 extdev/nodes.html Doctree node classes added by Sphinx +extdev/parserapi std:doc -1 extdev/parserapi.html Parser API +extdev/projectapi std:doc -1 extdev/projectapi.html Project API +extdev/utils std:doc -1 extdev/utils.html Utilities +extension std:term -1 glossary.html#term-$ - +extension-tutorials-index std:label -1 development/tutorials/index.html#$ Extension tutorials +extensions std:confval 1 usage/configuration.html#confval-$ - +extlinks std:confval 1 usage/extensions/extlinks.html#confval-$ - +extlinks_detect_hardcoded_links std:confval 1 usage/extensions/extlinks.html#confval-$ - +faq std:doc -1 faq.html Sphinx FAQ +faq std:label -1 faq.html#$ Sphinx FAQ +figure_language_filename std:confval 1 usage/configuration.html#confval-$ - +fresh-env std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +genindex std:label -1 genindex.html Index +get-started std:label -1 index.html#$ Get started +gettext_additional_targets std:confval 1 usage/configuration.html#confval-$ - +gettext_allow_fuzzy_translations std:confval 1 usage/configuration.html#confval-$ - +gettext_auto_build std:confval 1 usage/configuration.html#confval-$ - +gettext_compact std:confval 1 usage/configuration.html#confval-$ - +gettext_location std:confval 1 usage/configuration.html#confval-$ - +gettext_uuid std:confval 1 usage/configuration.html#confval-$ - +glossary std:doc -1 glossary.html Glossary +glossary std:label -1 glossary.html#$ Glossary +glossary-directive std:label -1 usage/restructuredtext/directives.html#$ Glossary +graphviz_dot std:confval 1 usage/extensions/graphviz.html#confval-$ - +graphviz_dot_args std:confval 1 usage/extensions/graphviz.html#confval-$ - +graphviz_output_format std:confval 1 usage/extensions/graphviz.html#confval-$ - +highlight_language std:confval 1 usage/configuration.html#confval-$ - +highlight_options std:confval 1 usage/configuration.html#confval-$ - +html-collect-pages std:event 1 extdev/appapi.html#event-$ - +html-meta std:label -1 usage/restructuredtext/basics.html#$ HTML Metadata +html-options std:label -1 usage/configuration.html#$ Options for HTML output +html-page-context std:event 1 extdev/appapi.html#event-$ - +html-themes std:label -1 usage/theming.html#$ HTML Theming +html4_writer std:confval 1 usage/configuration.html#confval-$ - +html_additional_pages std:confval 1 usage/configuration.html#confval-$ - +html_baseurl std:confval 1 usage/configuration.html#confval-$ - +html_codeblock_linenos_style std:confval 1 usage/configuration.html#confval-$ - +html_compact_lists std:confval 1 usage/configuration.html#confval-$ - +html_context std:confval 1 usage/configuration.html#confval-$ - +html_copy_source std:confval 1 usage/configuration.html#confval-$ - +html_css_files std:confval 1 usage/configuration.html#confval-$ - +html_domain_indices std:confval 1 usage/configuration.html#confval-$ - +html_experimental_html5_writer std:confval 1 usage/configuration.html#confval-$ - +html_extra_path std:confval 1 usage/configuration.html#confval-$ - +html_favicon std:confval 1 usage/configuration.html#confval-$ - +html_file_suffix std:confval 1 usage/configuration.html#confval-$ - +html_js_files std:confval 1 usage/configuration.html#confval-$ - +html_last_updated_fmt std:confval 1 usage/configuration.html#confval-$ - +html_link_suffix std:confval 1 usage/configuration.html#confval-$ - +html_logo std:confval 1 usage/configuration.html#confval-$ - +html_math_renderer std:confval 1 usage/configuration.html#confval-$ - +html_output_encoding std:confval 1 usage/configuration.html#confval-$ - +html_permalinks std:confval 1 usage/configuration.html#confval-$ - +html_permalinks_icon std:confval 1 usage/configuration.html#confval-$ - +html_scaled_image_link std:confval 1 usage/configuration.html#confval-$ - +html_search_language std:confval 1 usage/configuration.html#confval-$ - +html_search_options std:confval 1 usage/configuration.html#confval-$ - +html_search_scorer std:confval 1 usage/configuration.html#confval-$ - +html_secnumber_suffix std:confval 1 usage/configuration.html#confval-$ - +html_short_title std:confval 1 usage/configuration.html#confval-$ - +html_show_copyright std:confval 1 usage/configuration.html#confval-$ - +html_show_search_summary std:confval 1 usage/configuration.html#confval-$ - +html_show_sourcelink std:confval 1 usage/configuration.html#confval-$ - +html_show_sphinx std:confval 1 usage/configuration.html#confval-$ - +html_sidebars std:confval 1 usage/configuration.html#confval-$ - +html_sourcelink_suffix std:confval 1 usage/configuration.html#confval-$ - +html_split_index std:confval 1 usage/configuration.html#confval-$ - +html_static_path std:confval 1 usage/configuration.html#confval-$ - +html_style std:confval 1 usage/configuration.html#confval-$ - +html_theme std:confval 1 usage/configuration.html#confval-$ - +html_theme_options std:confval 1 usage/configuration.html#confval-$ - +html_theme_path std:confval 1 usage/configuration.html#confval-$ - +html_title std:confval 1 usage/configuration.html#confval-$ - +html_use_index std:confval 1 usage/configuration.html#confval-$ - +html_use_opensearch std:confval 1 usage/configuration.html#confval-$ - +html_use_smartypants std:confval 1 usage/configuration.html#confval-$ - +htmlhelp-options std:label -1 usage/configuration.html#$ Options for HTML help output +htmlhelp_basename std:confval 1 usage/configuration.html#confval-$ - +htmlhelp_file_suffix std:confval 1 usage/configuration.html#confval-$ - +htmlhelp_link_suffix std:confval 1 usage/configuration.html#confval-$ - +i18n-api std:label -1 extdev/i18n.html#$ i18n API +image_converter std:confval 1 usage/extensions/imgconverter.html#confval-$ - +image_converter_args std:confval 1 usage/extensions/imgconverter.html#confval-$ - +imgmath_add_tooltips std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_dvipng std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_dvipng_args std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_dvisvgm std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_dvisvgm_args std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_embed std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_font_size std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_image_format std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_latex std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_latex_args std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_latex_preamble std:confval 1 usage/extensions/math.html#confval-$ - +imgmath_use_preview std:confval 1 usage/extensions/math.html#confval-$ - +important-objects std:label -1 extdev/index.html#$ Important objects +include_patterns std:confval 1 usage/configuration.html#confval-$ - +index std:doc -1 index.html Welcome +info-field-lists std:label -1 usage/restructuredtext/domains.html#$ Info field lists +inheritance_alias std:confval 1 usage/extensions/inheritance.html#confval-$ - +inheritance_edge_attrs std:confval 1 usage/extensions/inheritance.html#confval-$ - +inheritance_graph_attrs std:confval 1 usage/extensions/inheritance.html#confval-$ - +inheritance_node_attrs std:confval 1 usage/extensions/inheritance.html#confval-$ - +install-pypi std:label -1 usage/installation.html#$ Installation from PyPI +internals/authors std:doc -1 internals/authors.html Sphinx authors +internals/code-of-conduct std:doc -1 internals/code-of-conduct.html Sphinx Code of Conduct +internals/contributing std:doc -1 internals/contributing.html Contributing to Sphinx +internals/index std:doc -1 internals/index.html Contribute to Sphinx +internals/organization std:doc -1 internals/organization.html Organization of the Sphinx project +internals/release-process std:doc -1 internals/release-process.html Sphinx’s release process +intersphinx_cache_limit std:confval 1 usage/extensions/intersphinx.html#confval-$ - +intersphinx_disabled_reftypes std:confval 1 usage/extensions/intersphinx.html#confval-$ - +intersphinx_mapping std:confval 1 usage/extensions/intersphinx.html#confval-$ - +intersphinx_timeout std:confval 1 usage/extensions/intersphinx.html#confval-$ - +intl std:label -1 usage/advanced/intl.html#$ Internationalization +intl-options std:label -1 usage/configuration.html#$ Options for internationalization +js-roles std:label -1 usage/restructuredtext/domains.html#$ - +jsmath_path std:confval 1 usage/extensions/math.html#confval-$ - +keep_warnings std:confval 1 usage/configuration.html#confval-$ - +language std:confval 1 usage/configuration.html#confval-$ - +latex std:doc -1 latex.html LaTeX customization +latex-macros std:label -1 latex.html#$ Macros +latex-options std:label -1 usage/configuration.html#$ Options for LaTeX output +latex_additional_files std:confval 1 usage/configuration.html#confval-$ - +latex_appendices std:confval 1 usage/configuration.html#confval-$ - +latex_docclass std:confval 1 usage/configuration.html#confval-$ - +latex_documents std:confval 1 usage/configuration.html#confval-$ - +latex_domain_indices std:confval 1 usage/configuration.html#confval-$ - +latex_elements std:confval 1 usage/configuration.html#confval-$ - +latex_elements_confval std:label -1 latex.html#latex-elements-confval The latex_elements configuration setting +latex_engine std:confval 1 usage/configuration.html#confval-$ - +latex_logo std:confval 1 usage/configuration.html#confval-$ - +latex_show_pagerefs std:confval 1 usage/configuration.html#confval-$ - +latex_show_urls std:confval 1 usage/configuration.html#confval-$ - +latex_table_style std:confval 1 usage/configuration.html#confval-$ - +latex_theme std:confval 1 usage/configuration.html#confval-$ - +latex_theme_options std:confval 1 usage/configuration.html#confval-$ - +latex_theme_path std:confval 1 usage/configuration.html#confval-$ - +latex_toplevel_sectioning std:confval 1 usage/configuration.html#confval-$ - +latex_use_latex_multicolumn std:confval 1 usage/configuration.html#confval-$ - +latex_use_xindy std:confval 1 usage/configuration.html#confval-$ - +latexcontainer std:label -1 latex.html#$ - +latexsphinxsetup std:label -1 latex.html#$ The sphinxsetup configuration setting +latexsphinxsetupforcewraps std:label -1 latex.html#$ verbatimforcewraps +latexsphinxsetuphmargin std:label -1 latex.html#$ hmargin, vmargin +lib option std:label -1 usage/configuration.html#lib-option - +link-index std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +linkcheck-process-uri std:event 1 extdev/appapi.html#event-$ - +linkcheck_allowed_redirects std:confval 1 usage/configuration.html#confval-$ - +linkcheck_anchors std:confval 1 usage/configuration.html#confval-$ - +linkcheck_anchors_ignore std:confval 1 usage/configuration.html#confval-$ - +linkcheck_auth std:confval 1 usage/configuration.html#confval-$ - +linkcheck_exclude_documents std:confval 1 usage/configuration.html#confval-$ - +linkcheck_ignore std:confval 1 usage/configuration.html#confval-$ - +linkcheck_rate_limit_timeout std:confval 1 usage/configuration.html#confval-$ - +linkcheck_request_headers std:confval 1 usage/configuration.html#confval-$ - +linkcheck_retries std:confval 1 usage/configuration.html#confval-$ - +linkcheck_timeout std:confval 1 usage/configuration.html#confval-$ - +linkcheck_workers std:confval 1 usage/configuration.html#confval-$ - +linkcode_resolve std:confval 1 usage/extensions/linkcode.html#confval-$ - +locale_dirs std:confval 1 usage/configuration.html#confval-$ - +logging-api std:label -1 extdev/logging.html#$ Logging API +make_mode std:label -1 man/sphinx-build.html#make-mode - +makefile_options std:label -1 man/sphinx-build.html#makefile-options Makefile Options +man-options std:label -1 usage/configuration.html#$ Options for manual page output +man/index std:doc -1 man/index.html Command-Line Tools +man/sphinx-apidoc std:doc -1 man/sphinx-apidoc.html sphinx-apidoc +man/sphinx-autogen std:doc -1 man/sphinx-autogen.html sphinx-autogen +man/sphinx-build std:doc -1 man/sphinx-build.html sphinx-build +man/sphinx-quickstart std:doc -1 man/sphinx-quickstart.html sphinx-quickstart +man_make_section_directory std:confval 1 usage/configuration.html#confval-$ - +man_pages std:confval 1 usage/configuration.html#confval-$ - +man_show_urls std:confval 1 usage/configuration.html#confval-$ - +manpages_url std:confval 1 usage/configuration.html#confval-$ - +markdown std:label -1 usage/markdown.html#$ Markdown +master document std:term -1 glossary.html#term-master-document - +master_doc std:confval 1 usage/configuration.html#confval-$ - +math-domain std:label -1 usage/restructuredtext/domains.html#$ The Math Domain +math-options std:label -1 usage/configuration.html#$ Options for Math +math-support std:label -1 usage/extensions/math.html#$ Math support for HTML outputs in Sphinx +math_eqref_format std:confval 1 usage/configuration.html#confval-$ - +math_number_all std:confval 1 usage/configuration.html#confval-$ - +math_numfig std:confval 1 usage/configuration.html#confval-$ - +mathjax2_config std:confval 1 usage/extensions/math.html#confval-$ - +mathjax3_config std:confval 1 usage/extensions/math.html#confval-$ - +mathjax_config std:confval 1 usage/extensions/math.html#confval-$ - +mathjax_options std:confval 1 usage/extensions/math.html#confval-$ - +mathjax_path std:confval 1 usage/extensions/math.html#confval-$ - +metadata std:label -1 usage/restructuredtext/field-lists.html#$ File-wide metadata +missing-reference std:event 1 extdev/appapi.html#event-$ - +modindex std:label -1 py-modindex.html Module Index +modindex_common_prefix std:confval 1 usage/configuration.html#confval-$ - +napoleon_attr_annotations std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_custom_sections std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_google_docstring std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_include_init_with_doc std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_include_private_with_doc std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_include_special_with_doc std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_numpy_docstring std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_preprocess_types std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_type_aliases std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_use_admonition_for_examples std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_use_admonition_for_notes std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_use_admonition_for_references std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_use_ivar std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_use_keyword std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_use_param std:confval 1 usage/extensions/napoleon.html#confval-$ - +napoleon_use_rtype std:confval 1 usage/extensions/napoleon.html#confval-$ - +needs_extensions std:confval 1 usage/configuration.html#confval-$ - +needs_sphinx std:confval 1 usage/configuration.html#confval-$ - +nitpick_ignore std:confval 1 usage/configuration.html#confval-$ - +nitpick_ignore_regex std:confval 1 usage/configuration.html#confval-$ - +nitpicky std:confval 1 usage/configuration.html#confval-$ - +nitpicky std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +nodes std:label -1 extdev/nodes.html#$ Doctree node classes added by Sphinx +numfig std:confval 1 usage/configuration.html#confval-$ - +numfig_format std:confval 1 usage/configuration.html#confval-$ - +numfig_secnum_depth std:confval 1 usage/configuration.html#confval-$ - +object std:term -1 glossary.html#term-$ - +object-description-transform std:event 1 extdev/appapi.html#event-$ - +option_emphasise_placeholders std:confval 1 usage/configuration.html#confval-$ - +parser-api std:label -1 extdev/parserapi.html#$ Parser API +pdb std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +primary_domain std:confval 1 usage/configuration.html#confval-$ - +project std:confval 1 usage/configuration.html#confval-$ - +project std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +project-api std:label -1 extdev/projectapi.html#$ Project API +project_copyright std:confval 1 usage/configuration.html#confval-$ - +publishing-sources std:label -1 tutorial/deploying.html#$ Publishing your documentation sources +py-modindex std:label -1 py-modindex.html Python Module Index +pygments_style std:confval 1 usage/configuration.html#confval-$ - +python-domain std:label -1 usage/restructuredtext/domains.html#$ The Python Domain +python-roles std:label -1 usage/restructuredtext/domains.html#$ Cross-referencing Python objects +python_use_unqualified_type_names std:confval 1 usage/configuration.html#confval-$ - +qthelp-options std:label -1 usage/configuration.html#$ Options for QtHelp output +qthelp_basename std:confval 1 usage/configuration.html#confval-$ - +qthelp_namespace std:confval 1 usage/configuration.html#confval-$ - +qthelp_theme std:confval 1 usage/configuration.html#confval-$ - +qthelp_theme_options std:confval 1 usage/configuration.html#confval-$ - +reStructuredText std:term -1 glossary.html#term-$ - +ref-role std:label -1 usage/restructuredtext/roles.html#$ Cross-referencing arbitrary locations +release std:confval 1 usage/configuration.html#confval-$ - +release std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +role std:term -1 glossary.html#term-$ - +root document std:term -1 glossary.html#term-root-document - +root_doc std:confval 1 usage/configuration.html#confval-$ - +rst-directives std:label -1 usage/restructuredtext/basics.html#$ Directives +rst-doctest-blocks std:label -1 usage/restructuredtext/basics.html#$ Doctest blocks +rst-field-lists std:label -1 usage/restructuredtext/basics.html#$ Field Lists +rst-index std:label -1 usage/restructuredtext/index.html#$ reStructuredText +rst-inline-markup std:label -1 usage/restructuredtext/basics.html#$ Inline markup +rst-literal-blocks std:label -1 usage/restructuredtext/basics.html#$ Literal blocks +rst-primer std:label -1 usage/restructuredtext/basics.html#$ reStructuredText Primer +rst-roles std:label -1 usage/restructuredtext/domains.html#$ - +rst-roles-alt std:label -1 usage/restructuredtext/basics.html#$ Roles +rst-sections std:label -1 usage/restructuredtext/basics.html#$ Sections +rst-tables std:label -1 usage/restructuredtext/basics.html#$ Tables +rst_epilog std:confval 1 usage/configuration.html#confval-$ - +rst_prolog std:confval 1 usage/configuration.html#confval-$ - +rstclass std:label -1 usage/restructuredtext/basics.html#$ - +search std:label -1 search.html Search Page +searchadapters std:label -1 usage/advanced/websupport/searchadapters.html#$ Search Adapters +sections std:label -1 usage/extensions/napoleon.html#$ Docstring Sections +serialization-details std:label -1 usage/builders/index.html#$ Serialization builder details +setuptools std:label -1 usage/advanced/setuptools.html#$ Setuptools integration +show_authors std:confval 1 usage/configuration.html#confval-$ - +signatures std:label -1 usage/restructuredtext/domains.html#$ Python Signatures +singlehtml_sidebars std:confval 1 usage/configuration.html#confval-$ - +smartquotes std:confval 1 usage/configuration.html#confval-$ - +smartquotes_action std:confval 1 usage/configuration.html#confval-$ - +smartquotes_excludes std:confval 1 usage/configuration.html#confval-$ - +source directory std:term -1 glossary.html#term-source-directory - +source-dir std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +source-read std:event 1 extdev/appapi.html#event-$ - +source_encoding std:confval 1 usage/configuration.html#confval-$ - +source_parsers std:confval 1 usage/configuration.html#confval-$ - +source_suffix std:confval 1 usage/configuration.html#confval-$ - +sphinx-apidoc.--dry-run std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-n - +sphinx-apidoc.--follow-links std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-l - +sphinx-apidoc.--force std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-f - +sphinx-apidoc.--full std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-F - +sphinx-apidoc.--implicit-namespaces std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-implicit-namespaces - +sphinx-apidoc.--module-first std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-M - +sphinx-apidoc.--no-headings std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-E - +sphinx-apidoc.--no-toc std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-T - +sphinx-apidoc.--private std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-P - +sphinx-apidoc.--separate std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-e - +sphinx-apidoc.--templatedir std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-0 - +sphinx-apidoc.--tocfile std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-tocfile - +sphinx-apidoc.-A std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-A - +sphinx-apidoc.-E std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-E - +sphinx-apidoc.-F std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-F - +sphinx-apidoc.-H std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-H - +sphinx-apidoc.-M std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-M - +sphinx-apidoc.-P std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-P - +sphinx-apidoc.-R std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-R - +sphinx-apidoc.-T std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-T - +sphinx-apidoc.-V std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-V - +sphinx-apidoc.-a std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-a - +sphinx-apidoc.-d std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-d - +sphinx-apidoc.-e std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-e - +sphinx-apidoc.-f std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-f - +sphinx-apidoc.-l std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-l - +sphinx-apidoc.-n std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-n - +sphinx-apidoc.-o std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-o - +sphinx-apidoc.-q std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-q - +sphinx-apidoc.-s std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-s - +sphinx-apidoc.-t std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-0 - +sphinx-autogen.--imported-members std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-i - +sphinx-autogen.--respect-module-all std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-a - +sphinx-autogen.--suffix std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-s - +sphinx-autogen.--templates std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-t - +sphinx-autogen.-a std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-a - +sphinx-autogen.-i std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-i - +sphinx-autogen.-o std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-o - +sphinx-autogen.-s std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-s - +sphinx-autogen.-t std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-t - +sphinx-build.--help std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-h - +sphinx-build.--keep-going std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-keep-going - +sphinx-build.--version std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-h - +sphinx-build.-A std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-A - +sphinx-build.-C std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-C - +sphinx-build.-D std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-D - +sphinx-build.-E std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-E - +sphinx-build.-M std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-M - +sphinx-build.-N std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-N - +sphinx-build.-P std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-P - +sphinx-build.-Q std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-Q - +sphinx-build.-T std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-T - +sphinx-build.-W std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-W - +sphinx-build.-a std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-a - +sphinx-build.-b std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-b - +sphinx-build.-c std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-c - +sphinx-build.-d std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-d - +sphinx-build.-h std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-h - +sphinx-build.-j std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-j - +sphinx-build.-n std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-n - +sphinx-build.-q std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-q - +sphinx-build.-t std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-t - +sphinx-build.-v std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-v - +sphinx-build.-w std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-w - +sphinx-quickstart.--author std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-a - +sphinx-quickstart.--batchfile std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-batchfile - +sphinx-quickstart.--dot std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-dot - +sphinx-quickstart.--ext-autodoc std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-autodoc - +sphinx-quickstart.--ext-coverage std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-coverage - +sphinx-quickstart.--ext-doctest std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-doctest - +sphinx-quickstart.--ext-githubpages std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-githubpages - +sphinx-quickstart.--ext-ifconfig std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-ifconfig - +sphinx-quickstart.--ext-imgmath std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-imgmath - +sphinx-quickstart.--ext-intersphinx std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-intersphinx - +sphinx-quickstart.--ext-mathjax std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-mathjax - +sphinx-quickstart.--ext-todo std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-todo - +sphinx-quickstart.--ext-viewcode std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-viewcode - +sphinx-quickstart.--extensions std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-extensions - +sphinx-quickstart.--help std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-h - +sphinx-quickstart.--language std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-l - +sphinx-quickstart.--makefile std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-makefile - +sphinx-quickstart.--master std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-master - +sphinx-quickstart.--no-batchfile std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-batchfile - +sphinx-quickstart.--no-makefile std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-makefile - +sphinx-quickstart.--no-sep std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-no-sep - +sphinx-quickstart.--no-use-make-mode std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-use-make-mode - +sphinx-quickstart.--project std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-p - +sphinx-quickstart.--quiet std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-q - +sphinx-quickstart.--release std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-r - +sphinx-quickstart.--sep std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-sep - +sphinx-quickstart.--suffix std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-suffix - +sphinx-quickstart.--templatedir std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-t - +sphinx-quickstart.--use-make-mode std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-use-make-mode - +sphinx-quickstart.--version std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-h - +sphinx-quickstart.-a std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-a - +sphinx-quickstart.-d std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-d - +sphinx-quickstart.-h std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-h - +sphinx-quickstart.-l std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-l - +sphinx-quickstart.-p std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-p - +sphinx-quickstart.-q std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-q - +sphinx-quickstart.-r std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-r - +sphinx-quickstart.-t std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-t - +sphinx-quickstart.-v std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-v - +sphinx.ext.imgconverter std:label -1 usage/extensions/imgconverter.html#sphinx-ext-imgconverter sphinx.ext.imgconverter – A reference image converter using Imagemagick +storagebackends std:label -1 usage/advanced/websupport/storagebackends.html#$ Storage Backends +strip_signature_backslash std:confval 1 usage/configuration.html#confval-$ - +support std:doc -1 support.html Get support +suppress_warnings std:confval 1 usage/configuration.html#confval-$ - +table-directives std:label -1 usage/restructuredtext/directives.html#$ Tables +tablecolors std:label -1 latex.html#$ TableRowColorHeader +tags std:label -1 usage/restructuredtext/directives.html#$ Including content based on tags +template-bridge std:label -1 extdev/appapi.html#$ The template bridge +template_bridge std:confval 1 usage/configuration.html#confval-$ - +templates_path std:confval 1 usage/configuration.html#confval-$ - +templating std:doc -1 templating.html Templating +templating std:label -1 templating.html#$ Templating +texinfo-faq std:label -1 faq.html#$ Texinfo info +texinfo-links std:label -1 faq.html#$ Displaying Links +texinfo-options std:label -1 usage/configuration.html#$ Options for Texinfo output +texinfo_appendices std:confval 1 usage/configuration.html#confval-$ - +texinfo_cross_references std:confval 1 usage/configuration.html#confval-$ - +texinfo_documents std:confval 1 usage/configuration.html#confval-$ - +texinfo_domain_indices std:confval 1 usage/configuration.html#confval-$ - +texinfo_elements std:confval 1 usage/configuration.html#confval-$ - +texinfo_no_detailmenu std:confval 1 usage/configuration.html#confval-$ - +texinfo_show_urls std:confval 1 usage/configuration.html#confval-$ - +text-options std:label -1 usage/configuration.html#$ Options for text output +text_add_secnumbers std:confval 1 usage/configuration.html#confval-$ - +text_newlines std:confval 1 usage/configuration.html#confval-$ - +text_secnumber_suffix std:confval 1 usage/configuration.html#confval-$ - +text_sectionchars std:confval 1 usage/configuration.html#confval-$ - +theming-static-templates std:label -1 development/theming.html#$ Static templates +third-party-extensions std:label -1 usage/extensions/index.html#$ Third-party extensions +third-party-themes std:label -1 usage/theming.html#$ Third Party Themes +tls_cacerts std:confval 1 usage/configuration.html#confval-$ - +tls_verify std:confval 1 usage/configuration.html#confval-$ - +toc_object_entries std:confval 1 usage/configuration.html#confval-$ - +toc_object_entries_show_parents std:confval 1 usage/configuration.html#confval-$ - +toctree-directive std:label -1 usage/restructuredtext/directives.html#$ Table of contents +today std:confval 1 usage/configuration.html#confval-$ - +today std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +today_fmt std:confval 1 usage/configuration.html#confval-$ - +todo-defined std:event 1 usage/extensions/todo.html#event-$ - +todo_emit_warnings std:confval 1 usage/extensions/todo.html#confval-$ - +todo_include_todos std:confval 1 usage/extensions/todo.html#confval-$ - +todo_link_only std:confval 1 usage/extensions/todo.html#confval-$ - +trim_doctest_flags std:confval 1 usage/configuration.html#confval-$ - +trim_footnote_reference_space std:confval 1 usage/configuration.html#confval-$ - +tutorial std:label -1 tutorial/index.html#$ Tutorial: Build your first project +tutorial-describing-objects std:label -1 tutorial/describing-code.html#$ Python +tutorial/automatic-doc-generation std:doc -1 tutorial/automatic-doc-generation.html Automatic documentation generation from code +tutorial/deploying std:doc -1 tutorial/deploying.html Appendix: Deploying a Sphinx project online +tutorial/describing-code std:doc -1 tutorial/describing-code.html Describing code in Sphinx +tutorial/end std:doc -1 tutorial/end.html Where to go from here +tutorial/first-steps std:doc -1 tutorial/first-steps.html First steps to document your project using Sphinx +tutorial/getting-started std:doc -1 tutorial/getting-started.html Getting started +tutorial/index std:doc -1 tutorial/index.html Tutorial: Build your first project +tutorial/more-sphinx-customization std:doc -1 tutorial/more-sphinx-customization.html More Sphinx customization +tutorial/narrative-documentation std:doc -1 tutorial/narrative-documentation.html Narrative documentation in Sphinx +type std:label -1 usage/configuration.html#$ - +usage/advanced/intl std:doc -1 usage/advanced/intl.html Internationalization +usage/advanced/setuptools std:doc -1 usage/advanced/setuptools.html Setuptools integration +usage/advanced/websupport/api std:doc -1 usage/advanced/websupport/api.html The WebSupport Class +usage/advanced/websupport/index std:doc -1 usage/advanced/websupport/index.html Sphinx Web Support +usage/advanced/websupport/quickstart std:doc -1 usage/advanced/websupport/quickstart.html Web Support Quick Start +usage/advanced/websupport/searchadapters std:doc -1 usage/advanced/websupport/searchadapters.html Search Adapters +usage/advanced/websupport/storagebackends std:doc -1 usage/advanced/websupport/storagebackends.html Storage Backends +usage/builders/index std:doc -1 usage/builders/index.html Builders +usage/configuration std:doc -1 usage/configuration.html Configuration +usage/extensions/autodoc std:doc -1 usage/extensions/autodoc.html sphinx.ext.autodoc – Include documentation from docstrings +usage/extensions/autosectionlabel std:doc -1 usage/extensions/autosectionlabel.html sphinx.ext.autosectionlabel – Allow reference sections using its title +usage/extensions/autosummary std:doc -1 usage/extensions/autosummary.html sphinx.ext.autosummary – Generate autodoc summaries +usage/extensions/coverage std:doc -1 usage/extensions/coverage.html sphinx.ext.coverage – Collect doc coverage stats +usage/extensions/doctest std:doc -1 usage/extensions/doctest.html sphinx.ext.doctest – Test snippets in the documentation +usage/extensions/duration std:doc -1 usage/extensions/duration.html sphinx.ext.duration – Measure durations of Sphinx processing +usage/extensions/example_google std:doc -1 usage/extensions/example_google.html Example Google Style Python Docstrings +usage/extensions/example_numpy std:doc -1 usage/extensions/example_numpy.html Example NumPy Style Python Docstrings +usage/extensions/extlinks std:doc -1 usage/extensions/extlinks.html sphinx.ext.extlinks – Markup to shorten external links +usage/extensions/githubpages std:doc -1 usage/extensions/githubpages.html sphinx.ext.githubpages – Publish HTML docs in GitHub Pages +usage/extensions/graphviz std:doc -1 usage/extensions/graphviz.html sphinx.ext.graphviz – Add Graphviz graphs +usage/extensions/ifconfig std:doc -1 usage/extensions/ifconfig.html sphinx.ext.ifconfig – Include content based on configuration +usage/extensions/imgconverter std:doc -1 usage/extensions/imgconverter.html sphinx.ext.imgconverter – A reference image converter using Imagemagick +usage/extensions/index std:doc -1 usage/extensions/index.html Extensions +usage/extensions/inheritance std:doc -1 usage/extensions/inheritance.html sphinx.ext.inheritance_diagram – Include inheritance diagrams +usage/extensions/intersphinx std:doc -1 usage/extensions/intersphinx.html sphinx.ext.intersphinx – Link to other projects’ documentation +usage/extensions/linkcode std:doc -1 usage/extensions/linkcode.html sphinx.ext.linkcode – Add external links to source code +usage/extensions/math std:doc -1 usage/extensions/math.html Math support for HTML outputs in Sphinx +usage/extensions/napoleon std:doc -1 usage/extensions/napoleon.html sphinx.ext.napoleon – Support for NumPy and Google style docstrings +usage/extensions/todo std:doc -1 usage/extensions/todo.html sphinx.ext.todo – Support for todo items +usage/extensions/viewcode std:doc -1 usage/extensions/viewcode.html sphinx.ext.viewcode – Add links to highlighted source code +usage/index std:doc -1 usage/index.html Using Sphinx +usage/installation std:doc -1 usage/installation.html Installing Sphinx +usage/markdown std:doc -1 usage/markdown.html Markdown +usage/quickstart std:doc -1 usage/quickstart.html Getting Started +usage/restructuredtext/basics std:doc -1 usage/restructuredtext/basics.html reStructuredText Primer +usage/restructuredtext/directives std:doc -1 usage/restructuredtext/directives.html Directives +usage/restructuredtext/domains std:doc -1 usage/restructuredtext/domains.html Domains +usage/restructuredtext/field-lists std:doc -1 usage/restructuredtext/field-lists.html Field Lists +usage/restructuredtext/index std:doc -1 usage/restructuredtext/index.html reStructuredText +usage/restructuredtext/roles std:doc -1 usage/restructuredtext/roles.html Roles +usage/theming std:doc -1 usage/theming.html HTML Theming +user-guides std:label -1 index.html#$ User Guides +user_agent std:confval 1 usage/configuration.html#confval-$ - +user_dic option std:label -1 usage/configuration.html#user-dic-option - +user_dic_enc option std:label -1 usage/configuration.html#user-dic-enc-option - +usingwith std:label -1 faq.html#$ Using Sphinx with… +version std:confval 1 usage/configuration.html#confval-$ - +version std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +viewcode-find-source std:event 1 usage/extensions/viewcode.html#event-$ - +viewcode-follow-imported std:event 1 usage/extensions/viewcode.html#event-$ - +viewcode_enable_epub std:confval 1 usage/extensions/viewcode.html#confval-$ - +viewcode_follow_imported_members std:confval 1 usage/extensions/viewcode.html#confval-$ - +warn-missing-reference std:event 1 extdev/appapi.html#event-$ - +warning-is-error std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - +websupport std:label -1 usage/advanced/websupport/index.html#$ Sphinx Web Support +websupportapi std:label -1 usage/advanced/websupport/api.html#$ The WebSupport Class +websupportquickstart std:label -1 usage/advanced/websupport/quickstart.html#$ Web Support Quick Start +when-deprecation-warnings-are-displayed std:label -1 man/sphinx-build.html#$ Deprecation Warnings +windows-other-method std:label -1 usage/installation.html#$ Other Methods +writing-builders std:label -1 extdev/builderapi.html#$ Builder API +xml_pretty std:confval 1 usage/configuration.html#confval-$ - +xref-syntax std:label -1 usage/restructuredtext/roles.html#$ Cross-referencing syntax diff --git a/tests/resource/objects_sphinx_1_6_6.inv b/tests/resource/objects_sphinx_1_6_6.inv new file mode 100644 index 0000000000000000000000000000000000000000..14e4893652ff7934427e70942a5537bdcff0b908 GIT binary patch literal 9674 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 MFNfa!KR&_h^KWeOCjbBd literal 0 HcmV?d00001 From 299aa918e905867680930be2f5a33f42fe4d3dc0 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 3 Nov 2022 15:18:24 -0400 Subject: [PATCH 074/106] Update tests for new objects_attrs.inv --- conftest.py | 4 ++-- tests/test_api_fail.py | 2 +- tests/test_api_good.py | 24 ++++++++++++------------ tests/test_cli.py | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/conftest.py b/conftest.py index b1c40962..7f783a7f 100644 --- a/conftest.py +++ b/conftest.py @@ -278,8 +278,8 @@ def func(inv, source_type): """ assert inv.project == "attrs" - assert inv.version == "17.2" - assert inv.count == 56 + assert inv.version == "22.1" + assert inv.count == 129 assert inv.source_type return func diff --git a/tests/test_api_fail.py b/tests/test_api_fail.py index aff99b11..4296fb20 100644 --- a/tests/test_api_fail.py +++ b/tests/test_api_fail.py @@ -141,7 +141,7 @@ def test_apifail_inventory_dictimport_toobig(self, path_fxn, res_dec): """Confirm error raised when JSON dict passed w/too many objects.""" inv = soi.Inventory(path_fxn(res_dec)) d = inv.json_dict() - d.update({"57": d["23"]}) + d.update({"4000": d["23"]}) with pytest.raises(ValueError): soi.Inventory(dict_json=d) diff --git a/tests/test_api_good.py b/tests/test_api_good.py index f11f5a13..540802cc 100644 --- a/tests/test_api_good.py +++ b/tests/test_api_good.py @@ -108,23 +108,23 @@ def test_api_decompress(self, path_fxn, scratch_path, misc_info, decomp_cmp_test [ 0, { # attr.Attribute py:class 1 api.html#$ - - soi.DataFields.Name: b"attr.Attribute", + soi.DataFields.Name: b"attr", soi.DataFields.Domain: b"py", - soi.DataFields.Role: b"class", - soi.DataFields.Priority: b"1", - soi.DataFields.URI: b"api.html#$", + soi.DataFields.Role: b"module", + soi.DataFields.Priority: b"0", + soi.DataFields.URI: b"index.html#module-$", soi.DataFields.DispName: b"-", }, ], [ -3, { # slots std:label -1 examples.html#$ Slots - soi.DataFields.Name: b"slots", + soi.DataFields.Name: b"validators", soi.DataFields.Domain: b"std", soi.DataFields.Role: b"label", soi.DataFields.Priority: b"-1", - soi.DataFields.URI: b"examples.html#$", - soi.DataFields.DispName: b"Slots", + soi.DataFields.URI: b"init.html#$", + soi.DataFields.DispName: b"Validators", }, ], ), @@ -133,7 +133,7 @@ def test_api_data_regex(self, element, datadict, bytes_txt, misc_info): """Confirm the regex for loading data lines is working properly.""" # Prelim approximate check to be sure we're working with the # correct file/data. - assert len(soi.re.pb_data.findall(bytes_txt)) == 56 + assert len(soi.re.pb_data.findall(bytes_txt)) == 129 mchs = list(soi.re.pb_data.finditer(bytes_txt)) @@ -444,13 +444,13 @@ def test_api_inventory_toosmallflatdict_importbutignore(self, res_dec): inv2 = soi.Inventory(d, count_error=False) - # 55 b/c the loop continues past missing elements - assert inv2.count == 55 + # 128 (one less than 129) b/c the loop continues past missing elements + assert inv2.count == 128 def test_api_inventory_namesuggest(self, res_cmp, check): """Confirm object name suggestion is nominally working on a specific object.""" - rst = ":py:function:`attr.evolve`" - idx = 6 + rst = ":py:function:`attr.attr.evolve`" + idx = 10 inv = soi.Inventory(str(res_cmp)) diff --git a/tests/test_cli.py b/tests/test_cli.py index ee47d1f2..cdfd4a47 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -354,7 +354,7 @@ def test_cli_suggest_withindex(self, run_cmdline_test, res_cmp): """Confirm with_index suggest works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-it", "50"]) - assert re.search("^.*instance_of\\S*\\s+23\\s*$", out_.getvalue(), re.M) + assert re.search("^.*instance_of\\S*\\s+82\\s*$", out_.getvalue(), re.M) @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_withscore(self, run_cmdline_test, res_cmp): @@ -368,11 +368,11 @@ def test_cli_suggest_withscoreandindex(self, run_cmdline_test, res_cmp): """Confirm with_index + with_score suggest works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-sit", "50"]) - re.search("^.*instance_of\\S*\\s+\\d+\\s+23\\s*$", out_.getvalue(), re.M) + re.search("^.*instance_of\\S*\\s+\\d+\\s+82\\s*$", out_.getvalue(), re.M) @pytest.mark.parametrize( ["inp", "flags", "nlines"], - [("", "-at", 56), ("y\n", "-t", 57), ("n\n", "-t", 1)], + [("", "-at", 129), ("y\n", "-t", 130), ("n\n", "-t", 1)], ) # Extra line for input() query in the "y\n" case @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_long_list(self, inp, flags, nlines, run_cmdline_test, res_cmp): @@ -392,9 +392,9 @@ def test_cli_suggest_many_results_stdin(self, res_cmp, run_cmdline_test): @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_paginated(self, res_cmp, run_cmdline_test): """Confirm pagination works as expected for a controlled example.""" - with stdio_mgr("\n\n") as (in_, out_, err_): + with stdio_mgr("\n" * 5) as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "function", "-sapt30"]) - assert 2 == out_.getvalue().count("Press Enter to continue") + assert 5 == out_.getvalue().count("Press Enter to continue") class TestFail: From c191de90af4650b218d7b5cde101fddbe6e0cf63 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 3 Nov 2022 15:50:45 -0400 Subject: [PATCH 075/106] Permit colon in object roles Update code and docs. Update objects count test for the new objects_sphinx.inv. --- doc/source/syntax.rst | 11 +- src/sphobjinv/re.py | 2 +- tests/resource/objects_sphinx.txt | 1475 ----------------------------- tests/test_api_good.py | 3 + tests/test_valid_objects.py | 5 +- 5 files changed, 16 insertions(+), 1480 deletions(-) delete mode 100644 tests/resource/objects_sphinx.txt diff --git a/doc/source/syntax.rst b/doc/source/syntax.rst index 65d9601a..a89e2614 100644 --- a/doc/source/syntax.rst +++ b/doc/source/syntax.rst @@ -106,16 +106,19 @@ the string ``zlib`` somewhere within it, but for consistency it should be exactl ``{role}`` The Sphinx role used when cross-referencing the object (falls between the - second and third colons; or, between the first and second colons if + second and third/last colons; or, between the first and second/last colons if using the |defdom|_). + Note that the role MAY contain a colon, as occurs with the + |rst-directive-option|_ directive in the Sphinx docs. + **Constraints** * **MUST** have nonzero length * **MUST** match a role defined in the domain referenced by ``{domain}`` - * **MUST NOT** contain whitespace or a colon + * **MUST NOT** contain whitespace * **RECOMMENDED** to consist of only ASCII word characters (``a-z``, ``A-Z``, ``0-9``, and ``_``) @@ -283,3 +286,7 @@ as in :obj:`This is join! `: .. |{uri}| replace:: ``{uri}`` .. |{dispname}| replace:: ``{dispname}`` + +.. |rst-directive-option| replace:: ``:rst:directive:option:`` + +.. _rst-directive-option: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-rst-directive-option diff --git a/src/sphobjinv/re.py b/src/sphobjinv/re.py index fbbe58a7..dfb7d203 100644 --- a/src/sphobjinv/re.py +++ b/src/sphobjinv/re.py @@ -70,7 +70,7 @@ \s+ # Dividing space (?P<{DF.Domain.value}>[^\s:]+) # --> Domain : # Dividing colon - (?P<{DF.Role.value}>[^\s:]+) # --> Role + (?P<{DF.Role.value}>[^\s]+) # --> Role \s+ # Dividing space (?P<{DF.Priority.value}>-?\d+) # --> Priority \s+? # Dividing space diff --git a/tests/resource/objects_sphinx.txt b/tests/resource/objects_sphinx.txt deleted file mode 100644 index 363079d9..00000000 --- a/tests/resource/objects_sphinx.txt +++ /dev/null @@ -1,1475 +0,0 @@ -# Sphinx inventory version 2 -# Project: Sphinx -# Version: 6.0.0b3 -# The remainder of this file is compressed using zlib. -@alias.data c:member 1 usage/restructuredtext/domains.html#c.$ [anonymous].data -@alias.f c:function 1 usage/restructuredtext/domains.html#c.$ [anonymous].f -@alias.f.k c:functionParam 1 usage/restructuredtext/domains.html#c.@alias.f [anonymous].f.k -Data c:struct 1 usage/restructuredtext/domains.html#c.$ - -Data.@data c:union 1 usage/restructuredtext/domains.html#c.$ Data.[anonymous] -Data.@data.a c:member 1 usage/restructuredtext/domains.html#c.$ Data.[anonymous].a -Data.@data.b c:member 1 usage/restructuredtext/domains.html#c.$ Data.[anonymous].b -PyType_GenericAlloc c:function 1 usage/restructuredtext/domains.html#c.$ - -PyType_GenericAlloc.nitems c:functionParam 1 usage/restructuredtext/domains.html#c.PyType_GenericAlloc - -PyType_GenericAlloc.type c:functionParam 1 usage/restructuredtext/domains.html#c.PyType_GenericAlloc - -a c:member 1 usage/restructuredtext/domains.html#c.$ - -f c:function 1 usage/restructuredtext/domains.html#c.$ - -f.i c:functionParam 1 usage/restructuredtext/domains.html#c.f - -CustomList cpp:type 1 tutorial/describing-code.html#_CPPv410$ - -Data cpp:class 1 usage/restructuredtext/domains.html#_CPPv44$ - -Data::@data cpp:union 1 usage/restructuredtext/domains.html#_CPPv4N4DataUt4_dataE Data::[anonymous] -Data::@data::a cpp:member 1 usage/restructuredtext/domains.html#_CPPv4N4DataUt4_data1aE Data::[anonymous]::a -Data::@data::b cpp:member 1 usage/restructuredtext/domains.html#_CPPv4N4DataUt4_data1bE Data::[anonymous]::b -MyContainer cpp:type 1 usage/restructuredtext/domains.html#_CPPv4I0E11$ - -MyContainer::T cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0E11MyContainer - -MyContainer::const_iterator cpp:type 1 usage/restructuredtext/domains.html#_CPPv4N11MyContainer14const_iteratorE - -MyList cpp:type 1 usage/restructuredtext/domains.html#_CPPv46$ - -MySortedContainer cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0EXNSt18LessThanComparableEI1TEE17$ - -MySortedContainer::T cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EXNSt18LessThanComparableEI1TEE17MySortedContainer - -MyType cpp:type 1 usage/restructuredtext/domains.html#_CPPv46$ - -Outer cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0E5$ - -Outer::Inner cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0EN5Outer5InnerE - -Outer::Inner::TInner cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EN5Outer5InnerE - -Outer::TOuter cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0E5Outer - -Outer cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0E5OuterIP1TE - -Outer::T cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0E5OuterIP1TE - -Outer cpp:class 1 usage/restructuredtext/domains.html#_CPPv4IE5OuterIiE - -Outer::Inner cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0EN5OuterIiE5InnerE - -Outer::Inner::TInner cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EN5OuterIiE5InnerE - -Outer::Inner cpp:class 1 usage/restructuredtext/domains.html#_CPPv4IEN5OuterIiE5InnerIbEE - -Wrapper cpp:class 1 usage/restructuredtext/domains.html#_CPPv47$ - -Wrapper::Outer cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0EN7Wrapper5OuterE - -Wrapper::Outer::Inner cpp:class 1 usage/restructuredtext/domains.html#_CPPv4I0EN7Wrapper5Outer5InnerE - -Wrapper::Outer::Inner::TInner cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EN7Wrapper5Outer5InnerE - -Wrapper::Outer::TOuter cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EN7Wrapper5OuterE - -a cpp:member 1 usage/restructuredtext/domains.html#_CPPv41$ - -advance cpp:function 1 usage/restructuredtext/domains.html#_CPPv4I0EXNSt8IteratorEI2ItEE7advancevR2It - -advance::It cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0EXNSt8IteratorEI2ItEE7advancevR2It - -advance::it cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv4I0EXNSt8IteratorEI2ItEE7advancevR2It - -f cpp:function 1 usage/restructuredtext/domains.html#_CPPv41fi - -f::i cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv41fi - -overload_example::C cpp:class 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1CE - -overload_example::C::f cpp:function 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEd - -overload_example::C::f cpp:function 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEi - -overload_example::C::f cpp:function 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEv - -overload_example::C::f cpp:function 1 usage/restructuredtext/domains.html#_CPPv4NK16overload_example1C1fEd - -overload_example::C::f::d cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEd - -overload_example::C::f::d cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv4NK16overload_example1C1fEd - -overload_example::C::f::i cpp:functionParam 1 usage/restructuredtext/domains.html#_CPPv4N16overload_example1C1fEi - -std::Iterator cpp:concept 1 usage/restructuredtext/domains.html#_CPPv4I0ENSt8IteratorE - -std::Iterator::It cpp:templateParam 1 usage/restructuredtext/domains.html#_CPPv4I0ENSt8IteratorE - -std::Iterator::r cpp:member 1 usage/restructuredtext/domains.html#_CPPv4NSt8Iterator1rE - -attributes py:data 1 usage/extensions/autosummary.html#$ - -body py:data 1 templating.html#$ - -builder py:data 1 templating.html#$ - -class py:data 1 usage/extensions/autosummary.html#$ - -classes py:data 1 usage/extensions/autosummary.html#$ - -conf py:module 0 usage/configuration.html#module-$ - -copyright py:data 1 templating.html#$ - -display_toc py:data 1 templating.html#$ - -docstitle py:data 1 templating.html#$ - -docutils.nodes.meta py:class -1 extdev/nodes.html#sphinx.addnodes.meta - -docutils.parsers.rst py:module 0 extdev/markupapi.html#module-$ - -docutils.parsers.rst.Directive py:class 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.arguments py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.block_text py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.content py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.content_offset py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.final_argument_whitespace py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.has_content py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.lineno py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.name py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.option_spec py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.optional_arguments py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.options py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.required_arguments py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.run py:method 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.state py:attribute 1 extdev/markupapi.html#$ - -docutils.parsers.rst.Directive.state_machine py:attribute 1 extdev/markupapi.html#$ - -docutils_version_info py:data 1 templating.html#$ - -embedded py:data 1 templating.html#$ - -enumerate py:function 1 usage/quickstart.html#$ - -escape py:function 1 usage/extensions/autosummary.html#$ - -exceptions py:data 1 usage/extensions/autosummary.html#$ - -favicon_url py:data 1 templating.html#$ - -file_suffix py:data 1 templating.html#$ - -fullname py:data 1 usage/extensions/autosummary.html#$ - -functions py:data 1 usage/extensions/autosummary.html#$ - -has_source py:data 1 templating.html#$ - -hasdoc py:function 1 templating.html#$ - -inherited_members py:data 1 usage/extensions/autosummary.html#$ - -language py:data 1 templating.html#$ - -last_updated py:data 1 templating.html#$ - -latex py:module 0 latex.html#module-$ - -logo_url py:data 1 templating.html#$ - -master_doc py:data 1 templating.html#$ - -members py:data 1 usage/extensions/autosummary.html#$ - -meta py:data 1 templating.html#$ - -metatags py:data 1 templating.html#$ - -methods py:data 1 usage/extensions/autosummary.html#$ - -module py:data 1 usage/extensions/autosummary.html#$ - -modules py:data 1 usage/extensions/autosummary.html#$ - -name py:data 1 usage/extensions/autosummary.html#$ - -next py:data 1 templating.html#$ - -objname py:data 1 usage/extensions/autosummary.html#$ - -page_source_suffix py:data 1 templating.html#$ - -pagename py:data 1 templating.html#$ - -parents py:data 1 templating.html#$ - -pathto py:function 1 templating.html#$ - -prev py:data 1 templating.html#$ - -project py:data 1 templating.html#$ - -relbar py:function 1 templating.html#$ - -reldelim1 py:data 1 templating.html#$ - -reldelim2 py:data 1 templating.html#$ - -release py:data 1 templating.html#$ - -rellinks py:data 1 templating.html#$ - -root_doc py:data 1 templating.html#$ - -script_files py:data 1 templating.html#$ - -shorttitle py:data 1 templating.html#$ - -show_source py:data 1 templating.html#$ - -sidebar py:function 1 templating.html#$ - -sourcename py:data 1 templating.html#$ - -sphinx.addnodes py:module 0 extdev/nodes.html#module-$ - -sphinx.addnodes.compact_paragraph py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_addname py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_annotation py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_content py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_inline py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_name py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_optional py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_parameter py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_parameterlist py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_returns py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_signature py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_signature_line py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.desc_type py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.download_reference py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.glossary py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.highlightlang py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.index py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.literal_emphasis py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.meta py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.only py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.pending_xref py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.pending_xref_condition py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.production py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.productionlist py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.seealso py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.start_of_file py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.toctree py:class 1 extdev/nodes.html#$ - -sphinx.addnodes.versionmodified py:class 1 extdev/nodes.html#$ - -sphinx.application py:module 0 extdev/appapi.html#module-$ - -sphinx.application.ExtensionError py:exception 1 extdev/appapi.html#$ - -sphinx.application.Sphinx py:class 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_autodoc_attrgetter py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_autodocumenter py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_builder py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_config_value py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_crossref_type py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_css_file py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_directive py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_directive_to_domain py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_domain py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_enumerable_node py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_env_collector py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_event py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_generic_role py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_html_math_renderer py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_html_theme py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_index_to_domain py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_js_file py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_latex_package py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_lexer py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_message_catalog py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_node py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_object_type py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_post_transform py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_role py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_role_to_domain py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_search_language py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_source_parser py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_source_suffix py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.add_transform py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.confdir py:attribute 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.connect py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.disconnect py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.doctreedir py:attribute 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.emit py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.emit_firstresult py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.is_parallel_allowed py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.outdir py:attribute 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.project py:attribute 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.require_sphinx py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.set_translator py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.setup_extension py:method 1 extdev/appapi.html#$ - -sphinx.application.Sphinx.srcdir py:attribute 1 extdev/appapi.html#$ - -sphinx.application.TemplateBridge py:class 1 extdev/appapi.html#$ - -sphinx.application.TemplateBridge.init py:method 1 extdev/appapi.html#$ - -sphinx.application.TemplateBridge.newest_template_mtime py:method 1 extdev/appapi.html#$ - -sphinx.application.TemplateBridge.render py:method 1 extdev/appapi.html#$ - -sphinx.application.TemplateBridge.render_string py:method 1 extdev/appapi.html#$ - -sphinx.builders py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.Builder py:class 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.allow_parallel py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.build py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.build_all py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.build_specific py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.build_update py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.default_translator_class py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.epilog py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.events py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.finish py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.format py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.get_outdated_docs py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.get_relative_uri py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.get_target_uri py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.init py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.name py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.prepare_writing py:method 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.supported_data_uri_images py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.supported_image_types py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.supported_remote_images py:attribute 1 extdev/builderapi.html#$ - -sphinx.builders.Builder.write_doc py:method 1 extdev/builderapi.html#$ - -sphinx.builders.changes py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.changes.ChangesBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.changes.ChangesBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.changes.ChangesBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.changes.ChangesBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.dirhtml py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.dirhtml.DirectoryHTMLBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.dirhtml.DirectoryHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.dirhtml.DirectoryHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.dirhtml.DirectoryHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.dummy py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.dummy.DummyBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.dummy.DummyBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.dummy.DummyBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.epub3 py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.epub3.Epub3Builder py:class 1 usage/builders/index.html#$ - -sphinx.builders.epub3.Epub3Builder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.epub3.Epub3Builder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.epub3.Epub3Builder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.gettext py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.gettext.MessageCatalogBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.gettext.MessageCatalogBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.gettext.MessageCatalogBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.gettext.MessageCatalogBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.html py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.html.StandaloneHTMLBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.html.StandaloneHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.html.StandaloneHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.html.StandaloneHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.latex py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.latex.LaTeXBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.latex.LaTeXBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.latex.LaTeXBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.latex.LaTeXBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.linkcheck py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.linkcheck.CheckExternalLinksBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.linkcheck.CheckExternalLinksBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.linkcheck.CheckExternalLinksBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.linkcheck.CheckExternalLinksBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.manpage py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.manpage.ManualPageBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.manpage.ManualPageBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.manpage.ManualPageBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.manpage.ManualPageBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.singlehtml py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.singlehtml.SingleFileHTMLBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.singlehtml.SingleFileHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.singlehtml.SingleFileHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.singlehtml.SingleFileHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.texinfo py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.texinfo.TexinfoBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.texinfo.TexinfoBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.texinfo.TexinfoBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.texinfo.TexinfoBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.text py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.text.TextBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.text.TextBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.text.TextBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.text.TextBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.xml py:module 0 usage/builders/index.html#module-$ - -sphinx.builders.xml.PseudoXMLBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.xml.PseudoXMLBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.xml.PseudoXMLBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.xml.PseudoXMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.xml.XMLBuilder py:class 1 usage/builders/index.html#$ - -sphinx.builders.xml.XMLBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.xml.XMLBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinx.builders.xml.XMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinx.config.Config py:class 1 extdev/appapi.html#$ - -sphinx.directives py:module 0 extdev/domainapi.html#module-$ - -sphinx.directives.ObjectDescription py:class 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription._object_hierarchy_parts py:method 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription._toc_entry_name py:method 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.add_target_and_index py:method 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.after_content py:method 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.before_content py:method 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.final_argument_whitespace py:attribute 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.get_signatures py:method 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.handle_signature py:method 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.has_content py:attribute 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.option_spec py:attribute 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.optional_arguments py:attribute 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.required_arguments py:attribute 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.run py:method 1 extdev/domainapi.html#$ - -sphinx.directives.ObjectDescription.transform_content py:method 1 extdev/domainapi.html#$ - -sphinx.domains py:module 0 extdev/domainapi.html#module-$ - -sphinx.domains.Domain py:class 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.add_object_type py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.check_consistency py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.clear_doc py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.dangling_warnings py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.data py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.data_version py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.directive py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.directives py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.enumerable_nodes py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.get_enumerable_node_type py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.get_full_qualified_name py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.get_objects py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.get_type_name py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.indices py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.initial_data py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.label py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.merge_domaindata py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.name py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.object_types py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.process_doc py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.process_field_xref py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.resolve_any_xref py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.resolve_xref py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.role py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.roles py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.Domain.setup py:method 1 extdev/domainapi.html#$ - -sphinx.domains.Index py:class 1 extdev/domainapi.html#$ - -sphinx.domains.Index.generate py:method 1 extdev/domainapi.html#$ - -sphinx.domains.ObjType py:class 1 extdev/domainapi.html#$ - -sphinx.domains.python py:module 0 extdev/domainapi.html#module-$ - -sphinx.domains.python.PythonDomain py:class 1 extdev/domainapi.html#$ - -sphinx.domains.python.PythonDomain.modules py:attribute 1 extdev/domainapi.html#$ - -sphinx.domains.python.PythonDomain.note_module py:method 1 extdev/domainapi.html#$ - -sphinx.domains.python.PythonDomain.note_object py:method 1 extdev/domainapi.html#$ - -sphinx.domains.python.PythonDomain.objects py:attribute 1 extdev/domainapi.html#$ - -sphinx.environment py:module 0 extdev/envapi.html#module-$ - -sphinx.environment.BuildEnvironment py:class 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.app py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.config py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.doc2path py:method 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.docname py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.doctreedir py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.events py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.found_docs py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.metadata py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.new_serialno py:method 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.note_dependency py:method 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.note_reread py:method 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.project py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.relfn2path py:method 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.srcdir py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.BuildEnvironment.titles py:attribute 1 extdev/envapi.html#$ - -sphinx.environment.collectors py:module 0 extdev/collectorapi.html#module-$ - -sphinx.environment.collectors.EnvironmentCollector py:class 1 extdev/collectorapi.html#$ - -sphinx.environment.collectors.EnvironmentCollector.clear_doc py:method 1 extdev/collectorapi.html#$ - -sphinx.environment.collectors.EnvironmentCollector.get_outdated_docs py:method 1 extdev/collectorapi.html#$ - -sphinx.environment.collectors.EnvironmentCollector.get_updated_docs py:method 1 extdev/collectorapi.html#$ - -sphinx.environment.collectors.EnvironmentCollector.merge_other py:method 1 extdev/collectorapi.html#$ - -sphinx.environment.collectors.EnvironmentCollector.process_doc py:method 1 extdev/collectorapi.html#$ - -sphinx.errors py:module 0 extdev/appapi.html#module-$ - -sphinx.errors.ConfigError py:exception 1 extdev/appapi.html#$ - -sphinx.errors.ExtensionError py:exception 1 extdev/appapi.html#$ - -sphinx.errors.SphinxError py:exception 1 extdev/appapi.html#$ - -sphinx.errors.SphinxError.category py:attribute 1 extdev/appapi.html#$ - -sphinx.errors.ThemeError py:exception 1 extdev/appapi.html#$ - -sphinx.errors.VersionRequirementError py:exception 1 extdev/appapi.html#$ - -sphinx.events.EventManager py:class 1 extdev/utils.html#$ - -sphinx.events.EventManager.add py:method 1 extdev/utils.html#$ - -sphinx.events.EventManager.connect py:method 1 extdev/utils.html#$ - -sphinx.events.EventManager.disconnect py:method 1 extdev/utils.html#$ - -sphinx.events.EventManager.emit py:method 1 extdev/utils.html#$ - -sphinx.events.EventManager.emit_firstresult py:method 1 extdev/utils.html#$ - -sphinx.ext.autodoc py:module 0 usage/extensions/autodoc.html#module-$ - -sphinx.ext.autodoc.between py:function 1 usage/extensions/autodoc.html#$ - -sphinx.ext.autodoc.cut_lines py:function 1 usage/extensions/autodoc.html#$ - -sphinx.ext.autosectionlabel py:module 0 usage/extensions/autosectionlabel.html#module-$ - -sphinx.ext.autosummary py:module 0 usage/extensions/autosummary.html#module-$ - -sphinx.ext.coverage py:module 0 usage/extensions/coverage.html#module-$ - -sphinx.ext.coverage.CoverageBuilder py:class 1 usage/extensions/coverage.html#$ - -sphinx.ext.doctest py:module 0 usage/extensions/doctest.html#module-$ - -sphinx.ext.duration py:module 0 usage/extensions/duration.html#module-$ - -sphinx.ext.extlinks py:module 0 usage/extensions/extlinks.html#module-$ - -sphinx.ext.githubpages py:module 0 usage/extensions/githubpages.html#module-$ - -sphinx.ext.graphviz py:module 0 usage/extensions/graphviz.html#module-$ - -sphinx.ext.ifconfig py:module 0 usage/extensions/ifconfig.html#module-$ - -sphinx.ext.imgconverter py:module 0 usage/extensions/imgconverter.html#module-$ - -sphinx.ext.imgmath py:module 0 usage/extensions/math.html#module-$ - -sphinx.ext.inheritance_diagram py:module 0 usage/extensions/inheritance.html#module-$ - -sphinx.ext.intersphinx py:module 0 usage/extensions/intersphinx.html#module-$ - -sphinx.ext.jsmath py:module 0 usage/extensions/math.html#module-$ - -sphinx.ext.linkcode py:module 0 usage/extensions/linkcode.html#module-$ - -sphinx.ext.mathbase py:module 0 usage/extensions/math.html#module-$ - -sphinx.ext.mathjax py:module 0 usage/extensions/math.html#module-$ - -sphinx.ext.napoleon py:module 0 usage/extensions/napoleon.html#module-$ - -sphinx.ext.todo py:module 0 usage/extensions/todo.html#module-$ - -sphinx.ext.viewcode py:module 0 usage/extensions/viewcode.html#module-$ - -sphinx.locale._ py:function 1 extdev/i18n.html#$ - -sphinx.locale.__ py:function 1 extdev/i18n.html#$ - -sphinx.locale.get_translation py:function 1 extdev/i18n.html#$ - -sphinx.locale.init py:function 1 extdev/i18n.html#$ - -sphinx.locale.init_console py:function 1 extdev/i18n.html#$ - -sphinx.parsers py:module 0 extdev/parserapi.html#module-$ - -sphinx.parsers.Parser py:class 1 extdev/parserapi.html#$ - -sphinx.parsers.Parser.config py:attribute 1 extdev/parserapi.html#$ - -sphinx.parsers.Parser.env py:attribute 1 extdev/parserapi.html#$ - -sphinx.parsers.Parser.set_application py:method 1 extdev/parserapi.html#$ - -sphinx.project.Project py:class 1 extdev/projectapi.html#$ - -sphinx.project.Project.discover py:method 1 extdev/projectapi.html#$ - -sphinx.project.Project.doc2path py:method 1 extdev/projectapi.html#$ - -sphinx.project.Project.docnames py:attribute 1 extdev/projectapi.html#$ - -sphinx.project.Project.path2doc py:method 1 extdev/projectapi.html#$ - -sphinx.project.Project.restore py:method 1 extdev/projectapi.html#$ - -sphinx.project.Project.source_suffix py:attribute 1 extdev/projectapi.html#$ - -sphinx.project.Project.srcdir py:attribute 1 extdev/projectapi.html#$ - -sphinx.transforms.SphinxTransform py:class 1 extdev/utils.html#$ - -sphinx.transforms.SphinxTransform.app py:property 1 extdev/utils.html#$ - -sphinx.transforms.SphinxTransform.config py:property 1 extdev/utils.html#$ - -sphinx.transforms.SphinxTransform.env py:property 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.SphinxPostTransform py:class 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.SphinxPostTransform.apply py:method 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.SphinxPostTransform.is_supported py:method 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.SphinxPostTransform.run py:method 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.images.ImageConverter py:class 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.images.ImageConverter.available py:attribute 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.images.ImageConverter.conversion_rules py:attribute 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.images.ImageConverter.convert py:method 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.images.ImageConverter.default_priority py:attribute 1 extdev/utils.html#$ - -sphinx.transforms.post_transforms.images.ImageConverter.is_available py:method 1 extdev/utils.html#$ - -sphinx.util.docutils.ReferenceRole py:class 1 extdev/utils.html#$ - -sphinx.util.docutils.ReferenceRole.disabled py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.ReferenceRole.has_explicit_title py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.ReferenceRole.target py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.ReferenceRole.title py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxDirective py:class 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxDirective.config py:property 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxDirective.env py:property 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxDirective.get_location py:method 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxDirective.get_source_info py:method 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxDirective.set_source_info py:method 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole py:class 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.config py:property 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.content py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.env py:property 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.get_location py:method 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.inliner py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.lineno py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.name py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.options py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.rawtext py:attribute 1 extdev/utils.html#$ - -sphinx.util.docutils.SphinxRole.text py:attribute 1 extdev/utils.html#$ - -sphinx.util.logging.SphinxLoggerAdapter py:class 1 extdev/logging.html#$ - -sphinx.util.logging.SphinxLoggerAdapter.critical py:method 1 extdev/logging.html#$ - -sphinx.util.logging.SphinxLoggerAdapter.debug py:method 1 extdev/logging.html#$ - -sphinx.util.logging.SphinxLoggerAdapter.error py:method 1 extdev/logging.html#$ - -sphinx.util.logging.SphinxLoggerAdapter.info py:method 1 extdev/logging.html#$ - -sphinx.util.logging.SphinxLoggerAdapter.log py:method 1 extdev/logging.html#$ - -sphinx.util.logging.SphinxLoggerAdapter.verbose py:method 1 extdev/logging.html#$ - -sphinx.util.logging.SphinxLoggerAdapter.warning py:method 1 extdev/logging.html#$ - -sphinx.util.logging.getLogger py:function 1 extdev/logging.html#$ - -sphinx.util.logging.pending_logging py:function 1 extdev/logging.html#$ - -sphinx.util.logging.pending_warnings py:function 1 extdev/logging.html#$ - -sphinx.util.logging.prefixed_warnings py:function 1 extdev/logging.html#$ - -sphinx.version_info py:data 1 extdev/appapi.html#$ - -sphinx_version py:data 1 templating.html#$ - -sphinx_version_tuple py:data 1 templating.html#$ - -sphinxcontrib.applehelp py:module 0 usage/builders/index.html#module-$ - -sphinxcontrib.applehelp.AppleHelpBuilder py:class 1 usage/builders/index.html#$ - -sphinxcontrib.applehelp.AppleHelpBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.applehelp.AppleHelpBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.applehelp.AppleHelpBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.devhelp py:module 0 usage/builders/index.html#module-$ - -sphinxcontrib.devhelp.DevhelpBuilder py:class 1 usage/builders/index.html#$ - -sphinxcontrib.devhelp.DevhelpBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.devhelp.DevhelpBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.devhelp.DevhelpBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.htmlhelp py:module 0 usage/builders/index.html#module-$ - -sphinxcontrib.htmlhelp.HTMLHelpBuilder py:class 1 usage/builders/index.html#$ - -sphinxcontrib.htmlhelp.HTMLHelpBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.htmlhelp.HTMLHelpBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.htmlhelp.HTMLHelpBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.qthelp py:module 0 usage/builders/index.html#module-$ - -sphinxcontrib.qthelp.QtHelpBuilder py:class 1 usage/builders/index.html#$ - -sphinxcontrib.qthelp.QtHelpBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.qthelp.QtHelpBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.qthelp.QtHelpBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.JSONHTMLBuilder py:class 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.JSONHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.JSONHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.JSONHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.PickleHTMLBuilder py:class 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.PickleHTMLBuilder.format py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.PickleHTMLBuilder.name py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.PickleHTMLBuilder.supported_image_types py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.SerializingHTMLBuilder py:class 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.SerializingHTMLBuilder.globalcontext_filename py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.SerializingHTMLBuilder.implementation py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.SerializingHTMLBuilder.out_suffix py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.serializinghtml.SerializingHTMLBuilder.searchindex_filename py:attribute 1 usage/builders/index.html#$ - -sphinxcontrib.websupport.WebSupport py:class 1 usage/advanced/websupport/api.html#$ - -sphinxcontrib.websupport.WebSupport.add_comment py:method 1 usage/advanced/websupport/api.html#$ - -sphinxcontrib.websupport.WebSupport.build py:method 1 usage/advanced/websupport/api.html#$ - -sphinxcontrib.websupport.WebSupport.get_data py:method 1 usage/advanced/websupport/api.html#$ - -sphinxcontrib.websupport.WebSupport.get_document py:method 1 usage/advanced/websupport/api.html#$ - -sphinxcontrib.websupport.WebSupport.get_search_results py:method 1 usage/advanced/websupport/api.html#$ - -sphinxcontrib.websupport.WebSupport.process_vote py:method 1 usage/advanced/websupport/api.html#$ - -sphinxcontrib.websupport.search.BaseSearch py:class 1 usage/advanced/websupport/searchadapters.html#$ - -sphinxcontrib.websupport.search.BaseSearch.add_document py:method 1 usage/advanced/websupport/searchadapters.html#$ - -sphinxcontrib.websupport.search.BaseSearch.extract_context py:method 1 usage/advanced/websupport/searchadapters.html#$ - -sphinxcontrib.websupport.search.BaseSearch.feed py:method 1 usage/advanced/websupport/searchadapters.html#$ - -sphinxcontrib.websupport.search.BaseSearch.finish_indexing py:method 1 usage/advanced/websupport/searchadapters.html#$ - -sphinxcontrib.websupport.search.BaseSearch.handle_query py:method 1 usage/advanced/websupport/searchadapters.html#$ - -sphinxcontrib.websupport.search.BaseSearch.init_indexing py:method 1 usage/advanced/websupport/searchadapters.html#$ - -sphinxcontrib.websupport.search.BaseSearch.query py:method 1 usage/advanced/websupport/searchadapters.html#$ - -sphinxcontrib.websupport.storage.StorageBackend py:class 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.accept_comment py:method 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.add_comment py:method 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.add_node py:method 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.delete_comment py:method 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.get_data py:method 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.post_build py:method 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.pre_build py:method 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.process_vote py:method 1 usage/advanced/websupport/storagebackends.html#$ - -sphinxcontrib.websupport.storage.StorageBackend.update_username py:method 1 usage/advanced/websupport/storagebackends.html#$ - -style py:data 1 templating.html#$ - -styles py:data 1 templating.html#$ - -title py:data 1 templating.html#$ - -toc py:data 1 templating.html#$ - -toctree py:data 1 templating.html#$ - -underline py:data 1 usage/extensions/autosummary.html#$ - -use_opensearch py:data 1 templating.html#$ - -version py:data 1 templating.html#$ - -warning py:function 1 templating.html#$ - -abbr rst:role 1 usage/restructuredtext/roles.html#role-$ - -any rst:role 1 usage/restructuredtext/roles.html#role-$ - -autoattribute rst:directive 1 usage/extensions/autodoc.html#directive-$ - -autoclass rst:directive 1 usage/extensions/autodoc.html#directive-$ - -autodata rst:directive 1 usage/extensions/autodoc.html#directive-$ - -autodecorator rst:directive 1 usage/extensions/autodoc.html#directive-$ - -autoexception rst:directive 1 usage/extensions/autodoc.html#directive-$ - -autofunction rst:directive 1 usage/extensions/autodoc.html#directive-$ - -automethod rst:directive 1 usage/extensions/autodoc.html#directive-$ - -automodule rst:directive 1 usage/extensions/autodoc.html#directive-$ - -automodule:members rst:directive:option 1 usage/extensions/autodoc.html#directive-option-automodule-members - -automodule:private-members rst:directive:option 1 usage/extensions/autodoc.html#directive-option-automodule-private-members - -automodule:special-members rst:directive:option 1 usage/extensions/autodoc.html#directive-option-automodule-special-members - -automodule:undoc-members rst:directive:option 1 usage/extensions/autodoc.html#directive-option-automodule-undoc-members - -autoproperty rst:directive 1 usage/extensions/autodoc.html#directive-$ - -autosummary rst:directive 1 usage/extensions/autosummary.html#directive-$ - -c:alias rst:directive 1 usage/restructuredtext/domains.html#directive-c-alias - -c:alias:maxdepth rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-c-alias-maxdepth - -c:alias:noroot rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-c-alias-noroot - -c:data rst:role 1 usage/restructuredtext/domains.html#role-c-data - -c:enum rst:directive 1 usage/restructuredtext/domains.html#directive-c-enum - -c:enum rst:role 1 usage/restructuredtext/domains.html#role-c-enum - -c:enumerator rst:directive 1 usage/restructuredtext/domains.html#directive-c-enumerator - -c:enumerator rst:role 1 usage/restructuredtext/domains.html#role-c-enumerator - -c:expr rst:role 1 usage/restructuredtext/domains.html#role-c-expr - -c:func rst:role 1 usage/restructuredtext/domains.html#role-c-func - -c:function rst:directive 1 usage/restructuredtext/domains.html#directive-c-function - -c:macro rst:directive 1 usage/restructuredtext/domains.html#directive-c-macro - -c:macro rst:role 1 usage/restructuredtext/domains.html#role-c-macro - -c:member rst:directive 1 usage/restructuredtext/domains.html#directive-c-member - -c:member rst:role 1 usage/restructuredtext/domains.html#role-c-member - -c:namespace rst:directive 1 usage/restructuredtext/domains.html#directive-c-namespace - -c:namespace-pop rst:directive 1 usage/restructuredtext/domains.html#directive-c-namespace-pop - -c:namespace-push rst:directive 1 usage/restructuredtext/domains.html#directive-c-namespace-push - -c:struct rst:directive 1 usage/restructuredtext/domains.html#directive-c-struct - -c:struct rst:role 1 usage/restructuredtext/domains.html#role-c-struct - -c:texpr rst:role 1 usage/restructuredtext/domains.html#role-c-texpr - -c:type rst:directive 1 usage/restructuredtext/domains.html#directive-c-type - -c:type rst:role 1 usage/restructuredtext/domains.html#role-c-type - -c:union rst:directive 1 usage/restructuredtext/domains.html#directive-c-union - -c:union rst:role 1 usage/restructuredtext/domains.html#role-c-union - -c:var rst:directive 1 usage/restructuredtext/domains.html#directive-c-var - -c:var rst:role 1 usage/restructuredtext/domains.html#role-c-var - -centered rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -code rst:role 1 usage/restructuredtext/roles.html#role-$ - -code-block rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -code-block:caption rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-caption - -code-block:class rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-class - -code-block:dedent rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-dedent - -code-block:emphasize-lines rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-emphasize-lines - -code-block:force rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-force - -code-block:lineno-start rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-lineno-start - -code-block:linenos rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-linenos - -code-block:name rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-code-block-name - -codeauthor rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -command rst:role 1 usage/restructuredtext/roles.html#role-$ - -cpp:alias rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-alias - -cpp:alias:maxdepth rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-cpp-alias-maxdepth - -cpp:alias:noroot rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-cpp-alias-noroot - -cpp:any rst:role 1 usage/restructuredtext/domains.html#role-cpp-any - -cpp:class rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-class - -cpp:class rst:role 1 usage/restructuredtext/domains.html#role-cpp-class - -cpp:concept rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-concept - -cpp:concept rst:role 1 usage/restructuredtext/domains.html#role-cpp-concept - -cpp:enum rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-enum - -cpp:enum rst:role 1 usage/restructuredtext/domains.html#role-cpp-enum - -cpp:enum-class rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-enum-class - -cpp:enum-struct rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-enum-struct - -cpp:enumerator rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-enumerator - -cpp:enumerator rst:role 1 usage/restructuredtext/domains.html#role-cpp-enumerator - -cpp:expr rst:role 1 usage/restructuredtext/domains.html#role-cpp-expr - -cpp:func rst:role 1 usage/restructuredtext/domains.html#role-cpp-func - -cpp:function rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-function - -cpp:member rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-member - -cpp:member rst:role 1 usage/restructuredtext/domains.html#role-cpp-member - -cpp:namespace rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-namespace - -cpp:namespace-pop rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-namespace-pop - -cpp:namespace-push rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-namespace-push - -cpp:struct rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-struct - -cpp:struct rst:role 1 usage/restructuredtext/domains.html#role-cpp-struct - -cpp:texpr rst:role 1 usage/restructuredtext/domains.html#role-cpp-texpr - -cpp:type rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-type - -cpp:type rst:role 1 usage/restructuredtext/domains.html#role-cpp-type - -cpp:union rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-union - -cpp:var rst:directive 1 usage/restructuredtext/domains.html#directive-cpp-var - -cpp:var rst:role 1 usage/restructuredtext/domains.html#role-cpp-var - -default-domain rst:directive 1 usage/restructuredtext/domains.html#directive-$ - -deprecated rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -describe rst:directive 1 usage/restructuredtext/domains.html#directive-$ - -dfn rst:role 1 usage/restructuredtext/roles.html#role-$ - -digraph rst:directive 1 usage/extensions/graphviz.html#directive-$ - -digraph:align rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-align - -digraph:alt rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-alt - -digraph:caption rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-caption - -digraph:class rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-class - -digraph:layout rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-layout - -digraph:name rst:directive:option 1 usage/extensions/graphviz.html#directive-option-digraph-name - -doc rst:role 1 usage/restructuredtext/roles.html#role-$ - -doctest rst:directive 1 usage/extensions/doctest.html#directive-$ - -download rst:role 1 usage/restructuredtext/roles.html#role-$ - -envvar rst:directive 1 usage/restructuredtext/domains.html#directive-$ - -envvar rst:role 1 usage/restructuredtext/roles.html#role-$ - -eq rst:role 1 usage/restructuredtext/roles.html#role-$ - -external rst:role 1 usage/extensions/intersphinx.html#role-$ - -file rst:role 1 usage/restructuredtext/roles.html#role-$ - -glossary rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -graph rst:directive 1 usage/extensions/graphviz.html#directive-$ - -graph:align rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-align - -graph:alt rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-alt - -graph:caption rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-caption - -graph:class rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-class - -graph:layout rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-layout - -graph:name rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graph-name - -graphviz rst:directive 1 usage/extensions/graphviz.html#directive-$ - -graphviz:align rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-align - -graphviz:alt rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-alt - -graphviz:caption rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-caption - -graphviz:class rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-class - -graphviz:layout rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-layout - -graphviz:name rst:directive:option 1 usage/extensions/graphviz.html#directive-option-graphviz-name - -guilabel rst:role 1 usage/restructuredtext/roles.html#role-$ - -highlight rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -highlight:force rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-highlight-force - -highlight:linenothreshold rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-highlight-linenothreshold - -hlist rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -ifconfig rst:directive 1 usage/extensions/ifconfig.html#directive-$ - -index rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -index rst:role 1 usage/restructuredtext/directives.html#role-$ - -index:name rst:directive:option 1 usage/restructuredtext/directives.html#directive-option-index-name - -inheritance-diagram rst:directive 1 usage/extensions/inheritance.html#directive-$ - -js:attr rst:role 1 usage/restructuredtext/domains.html#role-js-attr - -js:attribute rst:directive 1 usage/restructuredtext/domains.html#directive-js-attribute - -js:class rst:directive 1 usage/restructuredtext/domains.html#directive-js-class - -js:class rst:role 1 usage/restructuredtext/domains.html#role-js-class - -js:data rst:directive 1 usage/restructuredtext/domains.html#directive-js-data - -js:data rst:role 1 usage/restructuredtext/domains.html#role-js-data - -js:func rst:role 1 usage/restructuredtext/domains.html#role-js-func - -js:function rst:directive 1 usage/restructuredtext/domains.html#directive-js-function - -js:meth rst:role 1 usage/restructuredtext/domains.html#role-js-meth - -js:method rst:directive 1 usage/restructuredtext/domains.html#directive-js-method - -js:mod rst:role 1 usage/restructuredtext/domains.html#role-js-mod - -js:module rst:directive 1 usage/restructuredtext/domains.html#directive-js-module - -kbd rst:role 1 usage/restructuredtext/roles.html#role-$ - -keyword rst:role 1 usage/restructuredtext/roles.html#role-$ - -literalinclude rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -mailheader rst:role 1 usage/restructuredtext/roles.html#role-$ - -makevar rst:role 1 usage/restructuredtext/roles.html#role-$ - -manpage rst:role 1 usage/restructuredtext/roles.html#role-$ - -math rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -math rst:role 1 usage/restructuredtext/roles.html#role-$ - -math:numref rst:role 1 usage/restructuredtext/domains.html#role-math-numref - -menuselection rst:role 1 usage/restructuredtext/roles.html#role-$ - -mimetype rst:role 1 usage/restructuredtext/roles.html#role-$ - -newsgroup rst:role 1 usage/restructuredtext/roles.html#role-$ - -note rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -numref rst:role 1 usage/restructuredtext/roles.html#role-$ - -object rst:directive 1 usage/restructuredtext/domains.html#directive-$ - -only rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -option rst:directive 1 usage/restructuredtext/domains.html#directive-$ - -option rst:role 1 usage/restructuredtext/roles.html#role-$ - -pep rst:role 1 usage/restructuredtext/roles.html#role-$ - -productionlist rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -program rst:directive 1 usage/restructuredtext/domains.html#directive-$ - -program rst:role 1 usage/restructuredtext/roles.html#role-$ - -py:attr rst:role 1 usage/restructuredtext/domains.html#role-py-attr - -py:attribute rst:directive 1 usage/restructuredtext/domains.html#directive-py-attribute - -py:attribute:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-attribute-canonical - -py:attribute:type rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-attribute-type - -py:attribute:value rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-attribute-value - -py:class rst:directive 1 usage/restructuredtext/domains.html#directive-py-class - -py:class rst:role 1 usage/restructuredtext/domains.html#role-py-class - -py:class:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-class-canonical - -py:class:final rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-class-final - -py:classmethod rst:directive 1 usage/restructuredtext/domains.html#directive-py-classmethod - -py:const rst:role 1 usage/restructuredtext/domains.html#role-py-const - -py:currentmodule rst:directive 1 usage/restructuredtext/domains.html#directive-py-currentmodule - -py:data rst:directive 1 usage/restructuredtext/domains.html#directive-py-data - -py:data rst:role 1 usage/restructuredtext/domains.html#role-py-data - -py:data:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-data-canonical - -py:data:type rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-data-type - -py:data:value rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-data-value - -py:decorator rst:directive 1 usage/restructuredtext/domains.html#directive-py-decorator - -py:decoratormethod rst:directive 1 usage/restructuredtext/domains.html#directive-py-decoratormethod - -py:exc rst:role 1 usage/restructuredtext/domains.html#role-py-exc - -py:exception rst:directive 1 usage/restructuredtext/domains.html#directive-py-exception - -py:exception:final rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-exception-final - -py:func rst:role 1 usage/restructuredtext/domains.html#role-py-func - -py:function rst:directive 1 usage/restructuredtext/domains.html#directive-py-function - -py:function:async rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-function-async - -py:function:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-function-canonical - -py:meth rst:role 1 usage/restructuredtext/domains.html#role-py-meth - -py:method rst:directive 1 usage/restructuredtext/domains.html#directive-py-method - -py:method:abstractmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-abstractmethod - -py:method:async rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-async - -py:method:canonical rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-canonical - -py:method:classmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-classmethod - -py:method:final rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-final - -py:method:staticmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-method-staticmethod - -py:mod rst:role 1 usage/restructuredtext/domains.html#role-py-mod - -py:module rst:directive 1 usage/restructuredtext/domains.html#directive-py-module - -py:module:deprecated rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-module-deprecated - -py:module:platform rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-module-platform - -py:module:synopsis rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-module-synopsis - -py:obj rst:role 1 usage/restructuredtext/domains.html#role-py-obj - -py:property rst:directive 1 usage/restructuredtext/domains.html#directive-py-property - -py:property:abstractmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-property-abstractmethod - -py:property:classmethod rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-property-classmethod - -py:property:type rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-py-property-type - -py:staticmethod rst:directive 1 usage/restructuredtext/domains.html#directive-py-staticmethod - -ref rst:role 1 usage/restructuredtext/roles.html#role-$ - -regexp rst:role 1 usage/restructuredtext/roles.html#role-$ - -rfc rst:role 1 usage/restructuredtext/roles.html#role-$ - -rst:dir rst:role 1 usage/restructuredtext/domains.html#role-rst-dir - -rst:directive rst:directive 1 usage/restructuredtext/domains.html#directive-rst-directive - -rst:directive:option rst:directive 1 usage/restructuredtext/domains.html#directive-rst-directive-option - -rst:directive:option:type rst:directive:option 1 usage/restructuredtext/domains.html#directive-option-rst-directive-option-type - -rst:role rst:directive 1 usage/restructuredtext/domains.html#directive-rst-role - -rst:role rst:role 1 usage/restructuredtext/domains.html#role-rst-role - -rubric rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -samp rst:role 1 usage/restructuredtext/roles.html#role-$ - -sectionauthor rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -seealso rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -tabularcolumns rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -term rst:role 1 usage/restructuredtext/roles.html#role-$ - -testcleanup rst:directive 1 usage/extensions/doctest.html#directive-$ - -testcode rst:directive 1 usage/extensions/doctest.html#directive-$ - -testoutput rst:directive 1 usage/extensions/doctest.html#directive-$ - -testsetup rst:directive 1 usage/extensions/doctest.html#directive-$ - -toctree rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -todo rst:directive 1 usage/extensions/todo.html#directive-$ - -todolist rst:directive 1 usage/extensions/todo.html#directive-$ - -token rst:role 1 usage/restructuredtext/roles.html#role-$ - -versionadded rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -versionchanged rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -warning rst:directive 1 usage/restructuredtext/directives.html#directive-$ - -RemoveInSphinxXXXWarning std:term -1 glossary.html#term-$ - -SPHINX_APIDOC_OPTIONS std:envvar 1 man/sphinx-apidoc.html#envvar-$ - -add_function_parentheses std:confval 1 usage/configuration.html#confval-$ - -add_module_names std:confval 1 usage/configuration.html#confval-$ - -additionalcss std:label -1 latex.html#$ Additional CSS-like 'sphinxsetup' keys -all-files std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -any-role std:label -1 usage/restructuredtext/roles.html#$ Cross-referencing anything -applehelp-options std:label -1 usage/configuration.html#$ Options for Apple Help output -applehelp_bundle_id std:confval 1 usage/configuration.html#confval-$ - -applehelp_bundle_name std:confval 1 usage/configuration.html#confval-$ - -applehelp_bundle_version std:confval 1 usage/configuration.html#confval-$ - -applehelp_codesign_flags std:confval 1 usage/configuration.html#confval-$ - -applehelp_codesign_identity std:confval 1 usage/configuration.html#confval-$ - -applehelp_codesign_path std:confval 1 usage/configuration.html#confval-$ - -applehelp_dev_region std:confval 1 usage/configuration.html#confval-$ - -applehelp_disable_external_tools std:confval 1 usage/configuration.html#confval-$ - -applehelp_icon std:confval 1 usage/configuration.html#confval-$ - -applehelp_index_anchors std:confval 1 usage/configuration.html#confval-$ - -applehelp_indexer_path std:confval 1 usage/configuration.html#confval-$ - -applehelp_kb_product std:confval 1 usage/configuration.html#confval-$ - -applehelp_kb_url std:confval 1 usage/configuration.html#confval-$ - -applehelp_locale std:confval 1 usage/configuration.html#confval-$ - -applehelp_min_term_length std:confval 1 usage/configuration.html#confval-$ - -applehelp_remote_url std:confval 1 usage/configuration.html#confval-$ - -applehelp_stopwords std:confval 1 usage/configuration.html#confval-$ - -applehelp_title std:confval 1 usage/configuration.html#confval-$ - -author std:confval 1 usage/configuration.html#confval-$ - -authors std:label -1 internals/authors.html#$ Sphinx authors -autoclass_content std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc-before-process-signature std:event 1 usage/extensions/autodoc.html#event-$ - -autodoc-process-bases std:event 1 usage/extensions/autodoc.html#event-$ - -autodoc-process-docstring std:event 1 usage/extensions/autodoc.html#event-$ - -autodoc-process-signature std:event 1 usage/extensions/autodoc.html#event-$ - -autodoc-skip-member std:event 1 usage/extensions/autodoc.html#event-$ - -autodoc_class_signature std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_default_flags std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_default_options std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_docstring_signature std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_ext_tutorial std:label -1 development/tutorials/autodoc_ext.html#autodoc-ext-tutorial Developing autodoc extension for IntEnum -autodoc_inherit_docstrings std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_member_order std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_mock_imports std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_preserve_defaults std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_type_aliases std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_typehints std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_typehints_description_target std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_typehints_format std:confval 1 usage/extensions/autodoc.html#confval-$ - -autodoc_warningiserror std:confval 1 usage/extensions/autodoc.html#confval-$ - -autosectionlabel_maxdepth std:confval 1 usage/extensions/autosectionlabel.html#confval-$ - -autosectionlabel_prefix_document std:confval 1 usage/extensions/autosectionlabel.html#confval-$ - -autosummary-customizing-templates std:label -1 usage/extensions/autosummary.html#$ Customizing templates -autosummary_context std:confval 1 usage/extensions/autosummary.html#confval-$ - -autosummary_filename_map std:confval 1 usage/extensions/autosummary.html#confval-$ - -autosummary_generate std:confval 1 usage/extensions/autosummary.html#confval-$ - -autosummary_generate_overwrite std:confval 1 usage/extensions/autosummary.html#confval-$ - -autosummary_ignore_module_all std:confval 1 usage/extensions/autosummary.html#confval-$ - -autosummary_imported_members std:confval 1 usage/extensions/autosummary.html#confval-$ - -autosummary_mock_imports std:confval 1 usage/extensions/autosummary.html#confval-$ - -basic-domain-markup std:label -1 usage/restructuredtext/domains.html#$ Basic Markup -build-config std:label -1 usage/configuration.html#$ Configuration -build-dir std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -build-finished std:event 1 extdev/appapi.html#event-$ - -build-phases std:label -1 extdev/index.html#$ Build Phases -builder std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -builder std:term -1 glossary.html#term-$ - -builder-inited std:event 1 extdev/appapi.html#event-$ - -builders std:label -1 usage/builders/index.html#$ Builders -builtin-extensions std:label -1 usage/extensions/index.html#$ Built-in extensions -builtin-themes std:label -1 usage/theming.html#$ Builtin themes -c-config std:label -1 usage/configuration.html#$ Options for the C domain -c-domain std:label -1 usage/restructuredtext/domains.html#$ The C Domain -c-roles std:label -1 usage/restructuredtext/domains.html#$ Cross-referencing C constructs -c_extra_keywords std:confval 1 usage/configuration.html#confval-$ - -c_id_attributes std:confval 1 usage/configuration.html#confval-$ - -c_paren_attributes std:confval 1 usage/configuration.html#confval-$ - -changes std:doc -1 changes.html Changelog -changes std:label -1 changes.html#$ Changelog -code-examples std:label -1 usage/restructuredtext/directives.html#$ Showing code examples -code_of_conduct std:label -1 internals/code-of-conduct.html#code-of-conduct Sphinx Code of Conduct -collector-api std:label -1 extdev/collectorapi.html#$ Environment Collector API -conf-tags std:label -1 usage/configuration.html#$ - -config-dir std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -config-inited std:event 1 extdev/appapi.html#event-$ - -configuration directory std:term -1 glossary.html#term-configuration-directory - -contribute-get-started std:label -1 internals/contributing.html#$ Getting started -copyright std:confval 1 usage/configuration.html#confval-$ - -copyright std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -coverage_c_path std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_c_regexes std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_ignore_c_items std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_ignore_classes std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_ignore_functions std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_ignore_modules std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_ignore_pyobjects std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_show_missing_items std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_skip_undoc_in_source std:confval 1 usage/extensions/coverage.html#confval-$ - -coverage_write_headline std:confval 1 usage/extensions/coverage.html#confval-$ - -cpp-config std:label -1 usage/configuration.html#$ Options for the C++ domain -cpp-domain std:label -1 usage/restructuredtext/domains.html#$ The C++ Domain -cpp-roles std:label -1 usage/restructuredtext/domains.html#$ Cross-referencing -cpp_id_attributes std:confval 1 usage/configuration.html#confval-$ - -cpp_index_common_prefix std:confval 1 usage/configuration.html#confval-$ - -cpp_paren_attributes std:confval 1 usage/configuration.html#confval-$ - -default-substitutions std:label -1 usage/restructuredtext/roles.html#$ Substitutions -default_role std:confval 1 usage/configuration.html#confval-$ - -deprecation-policy std:label -1 internals/release-process.html#$ Deprecation policy -dev-deprecated-apis std:label -1 extdev/deprecated.html#$ Deprecated APIs -dev-extensions std:label -1 extdev/index.html#$ Developing extensions for Sphinx -development/builders std:doc -1 development/builders.html Configuring builders -development/index std:doc -1 development/index.html Extending Sphinx -development/overview std:doc -1 development/overview.html Developing extensions overview -development/theming std:doc -1 development/theming.html HTML theme development -development/tutorials/autodoc_ext std:doc -1 development/tutorials/autodoc_ext.html Developing autodoc extension for IntEnum -development/tutorials/examples/README std:doc -1 development/tutorials/examples/README.html Tutorial examples -development/tutorials/helloworld std:doc -1 development/tutorials/helloworld.html Developing a “Hello world” extension -development/tutorials/index std:doc -1 development/tutorials/index.html Extension tutorials -development/tutorials/recipe std:doc -1 development/tutorials/recipe.html Developing a “recipe” extension -development/tutorials/todo std:doc -1 development/tutorials/todo.html Developing a “TODO” extension -dic_enc option std:label -1 usage/configuration.html#dic-enc-option - -dict option std:label -1 usage/configuration.html#dict-option - -directive std:term -1 glossary.html#term-$ - -distribute-your-theme std:label -1 development/theming.html#$ Distribute your theme as a Python package -doctest_default_flags std:confval 1 usage/extensions/doctest.html#confval-$ - -doctest_global_cleanup std:confval 1 usage/extensions/doctest.html#confval-$ - -doctest_global_setup std:confval 1 usage/extensions/doctest.html#confval-$ - -doctest_path std:confval 1 usage/extensions/doctest.html#confval-$ - -doctest_test_doctest_blocks std:confval 1 usage/extensions/doctest.html#confval-$ - -doctree-read std:event 1 extdev/appapi.html#event-$ - -doctree-resolved std:event 1 extdev/appapi.html#event-$ - -document name std:term -1 glossary.html#term-document-name - -domain std:term -1 glossary.html#term-$ - -domain-api std:label -1 extdev/domainapi.html#$ Domain API -domains-std std:label -1 usage/restructuredtext/domains.html#$ The Standard Domain -env-before-read-docs std:event 1 extdev/appapi.html#event-$ - -env-check-consistency std:event 1 extdev/appapi.html#event-$ - -env-get-outdated std:event 1 extdev/appapi.html#event-$ - -env-merge-info std:event 1 extdev/appapi.html#event-$ - -env-purge-doc std:event 1 extdev/appapi.html#event-$ - -env-updated std:event 1 extdev/appapi.html#event-$ - -environment std:term -1 glossary.html#term-$ - -epub-faq std:label -1 faq.html#$ Epub info -epub-options std:label -1 usage/configuration.html#$ Options for epub output -epub_author std:confval 1 usage/configuration.html#confval-$ - -epub_basename std:confval 1 usage/configuration.html#confval-$ - -epub_contributor std:confval 1 usage/configuration.html#confval-$ - -epub_copyright std:confval 1 usage/configuration.html#confval-$ - -epub_cover std:confval 1 usage/configuration.html#confval-$ - -epub_css_files std:confval 1 usage/configuration.html#confval-$ - -epub_description std:confval 1 usage/configuration.html#confval-$ - -epub_exclude_files std:confval 1 usage/configuration.html#confval-$ - -epub_fix_images std:confval 1 usage/configuration.html#confval-$ - -epub_guide std:confval 1 usage/configuration.html#confval-$ - -epub_identifier std:confval 1 usage/configuration.html#confval-$ - -epub_language std:confval 1 usage/configuration.html#confval-$ - -epub_max_image_width std:confval 1 usage/configuration.html#confval-$ - -epub_post_files std:confval 1 usage/configuration.html#confval-$ - -epub_pre_files std:confval 1 usage/configuration.html#confval-$ - -epub_publisher std:confval 1 usage/configuration.html#confval-$ - -epub_scheme std:confval 1 usage/configuration.html#confval-$ - -epub_show_urls std:confval 1 usage/configuration.html#confval-$ - -epub_theme std:confval 1 usage/configuration.html#confval-$ - -epub_theme_options std:confval 1 usage/configuration.html#confval-$ - -epub_title std:confval 1 usage/configuration.html#confval-$ - -epub_tocdepth std:confval 1 usage/configuration.html#confval-$ - -epub_tocdup std:confval 1 usage/configuration.html#confval-$ - -epub_tocscope std:confval 1 usage/configuration.html#confval-$ - -epub_uid std:confval 1 usage/configuration.html#confval-$ - -epub_use_index std:confval 1 usage/configuration.html#confval-$ - -epub_writing_mode std:confval 1 usage/configuration.html#confval-$ - -events std:label -1 extdev/appapi.html#$ Sphinx core events -example_google std:label -1 usage/extensions/example_google.html#example-google Example Google Style Python Docstrings -example_numpy std:label -1 usage/extensions/example_numpy.html#example-numpy Example NumPy Style Python Docstrings -examples std:doc -1 examples.html Projects using Sphinx -examples std:label -1 examples.html#$ Projects using Sphinx -exceptions std:label -1 extdev/appapi.html#$ Exceptions -exclude_patterns std:confval 1 usage/configuration.html#confval-$ - -ext-i18n std:label -1 extdev/i18n.html#$ Extension internationalization (i18n) and localization (l10n) using i18n API -ext-metadata std:label -1 extdev/index.html#$ Extension metadata -extdev/appapi std:doc -1 extdev/appapi.html Application API -extdev/builderapi std:doc -1 extdev/builderapi.html Builder API -extdev/collectorapi std:doc -1 extdev/collectorapi.html Environment Collector API -extdev/deprecated std:doc -1 extdev/deprecated.html Deprecated APIs -extdev/domainapi std:doc -1 extdev/domainapi.html Domain API -extdev/envapi std:doc -1 extdev/envapi.html Build environment API -extdev/i18n std:doc -1 extdev/i18n.html i18n API -extdev/index std:doc -1 extdev/index.html Developing extensions for Sphinx -extdev/logging std:doc -1 extdev/logging.html Logging API -extdev/markupapi std:doc -1 extdev/markupapi.html Docutils markup API -extdev/nodes std:doc -1 extdev/nodes.html Doctree node classes added by Sphinx -extdev/parserapi std:doc -1 extdev/parserapi.html Parser API -extdev/projectapi std:doc -1 extdev/projectapi.html Project API -extdev/utils std:doc -1 extdev/utils.html Utilities -extension std:term -1 glossary.html#term-$ - -extension-tutorials-index std:label -1 development/tutorials/index.html#$ Extension tutorials -extensions std:confval 1 usage/configuration.html#confval-$ - -extlinks std:confval 1 usage/extensions/extlinks.html#confval-$ - -extlinks_detect_hardcoded_links std:confval 1 usage/extensions/extlinks.html#confval-$ - -faq std:doc -1 faq.html Sphinx FAQ -faq std:label -1 faq.html#$ Sphinx FAQ -figure_language_filename std:confval 1 usage/configuration.html#confval-$ - -fresh-env std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -genindex std:label -1 genindex.html Index -get-started std:label -1 index.html#$ Get started -gettext_additional_targets std:confval 1 usage/configuration.html#confval-$ - -gettext_allow_fuzzy_translations std:confval 1 usage/configuration.html#confval-$ - -gettext_auto_build std:confval 1 usage/configuration.html#confval-$ - -gettext_compact std:confval 1 usage/configuration.html#confval-$ - -gettext_location std:confval 1 usage/configuration.html#confval-$ - -gettext_uuid std:confval 1 usage/configuration.html#confval-$ - -glossary std:doc -1 glossary.html Glossary -glossary std:label -1 glossary.html#$ Glossary -glossary-directive std:label -1 usage/restructuredtext/directives.html#$ Glossary -graphviz_dot std:confval 1 usage/extensions/graphviz.html#confval-$ - -graphviz_dot_args std:confval 1 usage/extensions/graphviz.html#confval-$ - -graphviz_output_format std:confval 1 usage/extensions/graphviz.html#confval-$ - -highlight_language std:confval 1 usage/configuration.html#confval-$ - -highlight_options std:confval 1 usage/configuration.html#confval-$ - -html-collect-pages std:event 1 extdev/appapi.html#event-$ - -html-meta std:label -1 usage/restructuredtext/basics.html#$ HTML Metadata -html-options std:label -1 usage/configuration.html#$ Options for HTML output -html-page-context std:event 1 extdev/appapi.html#event-$ - -html-themes std:label -1 usage/theming.html#$ HTML Theming -html4_writer std:confval 1 usage/configuration.html#confval-$ - -html_additional_pages std:confval 1 usage/configuration.html#confval-$ - -html_baseurl std:confval 1 usage/configuration.html#confval-$ - -html_codeblock_linenos_style std:confval 1 usage/configuration.html#confval-$ - -html_compact_lists std:confval 1 usage/configuration.html#confval-$ - -html_context std:confval 1 usage/configuration.html#confval-$ - -html_copy_source std:confval 1 usage/configuration.html#confval-$ - -html_css_files std:confval 1 usage/configuration.html#confval-$ - -html_domain_indices std:confval 1 usage/configuration.html#confval-$ - -html_experimental_html5_writer std:confval 1 usage/configuration.html#confval-$ - -html_extra_path std:confval 1 usage/configuration.html#confval-$ - -html_favicon std:confval 1 usage/configuration.html#confval-$ - -html_file_suffix std:confval 1 usage/configuration.html#confval-$ - -html_js_files std:confval 1 usage/configuration.html#confval-$ - -html_last_updated_fmt std:confval 1 usage/configuration.html#confval-$ - -html_link_suffix std:confval 1 usage/configuration.html#confval-$ - -html_logo std:confval 1 usage/configuration.html#confval-$ - -html_math_renderer std:confval 1 usage/configuration.html#confval-$ - -html_output_encoding std:confval 1 usage/configuration.html#confval-$ - -html_permalinks std:confval 1 usage/configuration.html#confval-$ - -html_permalinks_icon std:confval 1 usage/configuration.html#confval-$ - -html_scaled_image_link std:confval 1 usage/configuration.html#confval-$ - -html_search_language std:confval 1 usage/configuration.html#confval-$ - -html_search_options std:confval 1 usage/configuration.html#confval-$ - -html_search_scorer std:confval 1 usage/configuration.html#confval-$ - -html_secnumber_suffix std:confval 1 usage/configuration.html#confval-$ - -html_short_title std:confval 1 usage/configuration.html#confval-$ - -html_show_copyright std:confval 1 usage/configuration.html#confval-$ - -html_show_search_summary std:confval 1 usage/configuration.html#confval-$ - -html_show_sourcelink std:confval 1 usage/configuration.html#confval-$ - -html_show_sphinx std:confval 1 usage/configuration.html#confval-$ - -html_sidebars std:confval 1 usage/configuration.html#confval-$ - -html_sourcelink_suffix std:confval 1 usage/configuration.html#confval-$ - -html_split_index std:confval 1 usage/configuration.html#confval-$ - -html_static_path std:confval 1 usage/configuration.html#confval-$ - -html_style std:confval 1 usage/configuration.html#confval-$ - -html_theme std:confval 1 usage/configuration.html#confval-$ - -html_theme_options std:confval 1 usage/configuration.html#confval-$ - -html_theme_path std:confval 1 usage/configuration.html#confval-$ - -html_title std:confval 1 usage/configuration.html#confval-$ - -html_use_index std:confval 1 usage/configuration.html#confval-$ - -html_use_opensearch std:confval 1 usage/configuration.html#confval-$ - -html_use_smartypants std:confval 1 usage/configuration.html#confval-$ - -htmlhelp-options std:label -1 usage/configuration.html#$ Options for HTML help output -htmlhelp_basename std:confval 1 usage/configuration.html#confval-$ - -htmlhelp_file_suffix std:confval 1 usage/configuration.html#confval-$ - -htmlhelp_link_suffix std:confval 1 usage/configuration.html#confval-$ - -i18n-api std:label -1 extdev/i18n.html#$ i18n API -image_converter std:confval 1 usage/extensions/imgconverter.html#confval-$ - -image_converter_args std:confval 1 usage/extensions/imgconverter.html#confval-$ - -imgmath_add_tooltips std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_dvipng std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_dvipng_args std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_dvisvgm std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_dvisvgm_args std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_embed std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_font_size std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_image_format std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_latex std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_latex_args std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_latex_preamble std:confval 1 usage/extensions/math.html#confval-$ - -imgmath_use_preview std:confval 1 usage/extensions/math.html#confval-$ - -important-objects std:label -1 extdev/index.html#$ Important objects -include_patterns std:confval 1 usage/configuration.html#confval-$ - -index std:doc -1 index.html Welcome -info-field-lists std:label -1 usage/restructuredtext/domains.html#$ Info field lists -inheritance_alias std:confval 1 usage/extensions/inheritance.html#confval-$ - -inheritance_edge_attrs std:confval 1 usage/extensions/inheritance.html#confval-$ - -inheritance_graph_attrs std:confval 1 usage/extensions/inheritance.html#confval-$ - -inheritance_node_attrs std:confval 1 usage/extensions/inheritance.html#confval-$ - -install-pypi std:label -1 usage/installation.html#$ Installation from PyPI -internals/authors std:doc -1 internals/authors.html Sphinx authors -internals/code-of-conduct std:doc -1 internals/code-of-conduct.html Sphinx Code of Conduct -internals/contributing std:doc -1 internals/contributing.html Contributing to Sphinx -internals/index std:doc -1 internals/index.html Contribute to Sphinx -internals/organization std:doc -1 internals/organization.html Organization of the Sphinx project -internals/release-process std:doc -1 internals/release-process.html Sphinx’s release process -intersphinx_cache_limit std:confval 1 usage/extensions/intersphinx.html#confval-$ - -intersphinx_disabled_reftypes std:confval 1 usage/extensions/intersphinx.html#confval-$ - -intersphinx_mapping std:confval 1 usage/extensions/intersphinx.html#confval-$ - -intersphinx_timeout std:confval 1 usage/extensions/intersphinx.html#confval-$ - -intl std:label -1 usage/advanced/intl.html#$ Internationalization -intl-options std:label -1 usage/configuration.html#$ Options for internationalization -js-roles std:label -1 usage/restructuredtext/domains.html#$ - -jsmath_path std:confval 1 usage/extensions/math.html#confval-$ - -keep_warnings std:confval 1 usage/configuration.html#confval-$ - -language std:confval 1 usage/configuration.html#confval-$ - -latex std:doc -1 latex.html LaTeX customization -latex-macros std:label -1 latex.html#$ Macros -latex-options std:label -1 usage/configuration.html#$ Options for LaTeX output -latex_additional_files std:confval 1 usage/configuration.html#confval-$ - -latex_appendices std:confval 1 usage/configuration.html#confval-$ - -latex_docclass std:confval 1 usage/configuration.html#confval-$ - -latex_documents std:confval 1 usage/configuration.html#confval-$ - -latex_domain_indices std:confval 1 usage/configuration.html#confval-$ - -latex_elements std:confval 1 usage/configuration.html#confval-$ - -latex_elements_confval std:label -1 latex.html#latex-elements-confval The latex_elements configuration setting -latex_engine std:confval 1 usage/configuration.html#confval-$ - -latex_logo std:confval 1 usage/configuration.html#confval-$ - -latex_show_pagerefs std:confval 1 usage/configuration.html#confval-$ - -latex_show_urls std:confval 1 usage/configuration.html#confval-$ - -latex_table_style std:confval 1 usage/configuration.html#confval-$ - -latex_theme std:confval 1 usage/configuration.html#confval-$ - -latex_theme_options std:confval 1 usage/configuration.html#confval-$ - -latex_theme_path std:confval 1 usage/configuration.html#confval-$ - -latex_toplevel_sectioning std:confval 1 usage/configuration.html#confval-$ - -latex_use_latex_multicolumn std:confval 1 usage/configuration.html#confval-$ - -latex_use_xindy std:confval 1 usage/configuration.html#confval-$ - -latexcontainer std:label -1 latex.html#$ - -latexsphinxsetup std:label -1 latex.html#$ The sphinxsetup configuration setting -latexsphinxsetupforcewraps std:label -1 latex.html#$ verbatimforcewraps -latexsphinxsetuphmargin std:label -1 latex.html#$ hmargin, vmargin -lib option std:label -1 usage/configuration.html#lib-option - -link-index std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -linkcheck-process-uri std:event 1 extdev/appapi.html#event-$ - -linkcheck_allowed_redirects std:confval 1 usage/configuration.html#confval-$ - -linkcheck_anchors std:confval 1 usage/configuration.html#confval-$ - -linkcheck_anchors_ignore std:confval 1 usage/configuration.html#confval-$ - -linkcheck_auth std:confval 1 usage/configuration.html#confval-$ - -linkcheck_exclude_documents std:confval 1 usage/configuration.html#confval-$ - -linkcheck_ignore std:confval 1 usage/configuration.html#confval-$ - -linkcheck_rate_limit_timeout std:confval 1 usage/configuration.html#confval-$ - -linkcheck_request_headers std:confval 1 usage/configuration.html#confval-$ - -linkcheck_retries std:confval 1 usage/configuration.html#confval-$ - -linkcheck_timeout std:confval 1 usage/configuration.html#confval-$ - -linkcheck_workers std:confval 1 usage/configuration.html#confval-$ - -linkcode_resolve std:confval 1 usage/extensions/linkcode.html#confval-$ - -locale_dirs std:confval 1 usage/configuration.html#confval-$ - -logging-api std:label -1 extdev/logging.html#$ Logging API -make_mode std:label -1 man/sphinx-build.html#make-mode - -makefile_options std:label -1 man/sphinx-build.html#makefile-options Makefile Options -man-options std:label -1 usage/configuration.html#$ Options for manual page output -man/index std:doc -1 man/index.html Command-Line Tools -man/sphinx-apidoc std:doc -1 man/sphinx-apidoc.html sphinx-apidoc -man/sphinx-autogen std:doc -1 man/sphinx-autogen.html sphinx-autogen -man/sphinx-build std:doc -1 man/sphinx-build.html sphinx-build -man/sphinx-quickstart std:doc -1 man/sphinx-quickstart.html sphinx-quickstart -man_make_section_directory std:confval 1 usage/configuration.html#confval-$ - -man_pages std:confval 1 usage/configuration.html#confval-$ - -man_show_urls std:confval 1 usage/configuration.html#confval-$ - -manpages_url std:confval 1 usage/configuration.html#confval-$ - -markdown std:label -1 usage/markdown.html#$ Markdown -master document std:term -1 glossary.html#term-master-document - -master_doc std:confval 1 usage/configuration.html#confval-$ - -math-domain std:label -1 usage/restructuredtext/domains.html#$ The Math Domain -math-options std:label -1 usage/configuration.html#$ Options for Math -math-support std:label -1 usage/extensions/math.html#$ Math support for HTML outputs in Sphinx -math_eqref_format std:confval 1 usage/configuration.html#confval-$ - -math_number_all std:confval 1 usage/configuration.html#confval-$ - -math_numfig std:confval 1 usage/configuration.html#confval-$ - -mathjax2_config std:confval 1 usage/extensions/math.html#confval-$ - -mathjax3_config std:confval 1 usage/extensions/math.html#confval-$ - -mathjax_config std:confval 1 usage/extensions/math.html#confval-$ - -mathjax_options std:confval 1 usage/extensions/math.html#confval-$ - -mathjax_path std:confval 1 usage/extensions/math.html#confval-$ - -metadata std:label -1 usage/restructuredtext/field-lists.html#$ File-wide metadata -missing-reference std:event 1 extdev/appapi.html#event-$ - -modindex std:label -1 py-modindex.html Module Index -modindex_common_prefix std:confval 1 usage/configuration.html#confval-$ - -napoleon_attr_annotations std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_custom_sections std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_google_docstring std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_include_init_with_doc std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_include_private_with_doc std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_include_special_with_doc std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_numpy_docstring std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_preprocess_types std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_type_aliases std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_use_admonition_for_examples std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_use_admonition_for_notes std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_use_admonition_for_references std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_use_ivar std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_use_keyword std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_use_param std:confval 1 usage/extensions/napoleon.html#confval-$ - -napoleon_use_rtype std:confval 1 usage/extensions/napoleon.html#confval-$ - -needs_extensions std:confval 1 usage/configuration.html#confval-$ - -needs_sphinx std:confval 1 usage/configuration.html#confval-$ - -nitpick_ignore std:confval 1 usage/configuration.html#confval-$ - -nitpick_ignore_regex std:confval 1 usage/configuration.html#confval-$ - -nitpicky std:confval 1 usage/configuration.html#confval-$ - -nitpicky std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -nodes std:label -1 extdev/nodes.html#$ Doctree node classes added by Sphinx -numfig std:confval 1 usage/configuration.html#confval-$ - -numfig_format std:confval 1 usage/configuration.html#confval-$ - -numfig_secnum_depth std:confval 1 usage/configuration.html#confval-$ - -object std:term -1 glossary.html#term-$ - -object-description-transform std:event 1 extdev/appapi.html#event-$ - -option_emphasise_placeholders std:confval 1 usage/configuration.html#confval-$ - -parser-api std:label -1 extdev/parserapi.html#$ Parser API -pdb std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -primary_domain std:confval 1 usage/configuration.html#confval-$ - -project std:confval 1 usage/configuration.html#confval-$ - -project std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -project-api std:label -1 extdev/projectapi.html#$ Project API -project_copyright std:confval 1 usage/configuration.html#confval-$ - -publishing-sources std:label -1 tutorial/deploying.html#$ Publishing your documentation sources -py-modindex std:label -1 py-modindex.html Python Module Index -pygments_style std:confval 1 usage/configuration.html#confval-$ - -python-domain std:label -1 usage/restructuredtext/domains.html#$ The Python Domain -python-roles std:label -1 usage/restructuredtext/domains.html#$ Cross-referencing Python objects -python_use_unqualified_type_names std:confval 1 usage/configuration.html#confval-$ - -qthelp-options std:label -1 usage/configuration.html#$ Options for QtHelp output -qthelp_basename std:confval 1 usage/configuration.html#confval-$ - -qthelp_namespace std:confval 1 usage/configuration.html#confval-$ - -qthelp_theme std:confval 1 usage/configuration.html#confval-$ - -qthelp_theme_options std:confval 1 usage/configuration.html#confval-$ - -reStructuredText std:term -1 glossary.html#term-$ - -ref-role std:label -1 usage/restructuredtext/roles.html#$ Cross-referencing arbitrary locations -release std:confval 1 usage/configuration.html#confval-$ - -release std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -role std:term -1 glossary.html#term-$ - -root document std:term -1 glossary.html#term-root-document - -root_doc std:confval 1 usage/configuration.html#confval-$ - -rst-directives std:label -1 usage/restructuredtext/basics.html#$ Directives -rst-doctest-blocks std:label -1 usage/restructuredtext/basics.html#$ Doctest blocks -rst-field-lists std:label -1 usage/restructuredtext/basics.html#$ Field Lists -rst-index std:label -1 usage/restructuredtext/index.html#$ reStructuredText -rst-inline-markup std:label -1 usage/restructuredtext/basics.html#$ Inline markup -rst-literal-blocks std:label -1 usage/restructuredtext/basics.html#$ Literal blocks -rst-primer std:label -1 usage/restructuredtext/basics.html#$ reStructuredText Primer -rst-roles std:label -1 usage/restructuredtext/domains.html#$ - -rst-roles-alt std:label -1 usage/restructuredtext/basics.html#$ Roles -rst-sections std:label -1 usage/restructuredtext/basics.html#$ Sections -rst-tables std:label -1 usage/restructuredtext/basics.html#$ Tables -rst_epilog std:confval 1 usage/configuration.html#confval-$ - -rst_prolog std:confval 1 usage/configuration.html#confval-$ - -rstclass std:label -1 usage/restructuredtext/basics.html#$ - -search std:label -1 search.html Search Page -searchadapters std:label -1 usage/advanced/websupport/searchadapters.html#$ Search Adapters -sections std:label -1 usage/extensions/napoleon.html#$ Docstring Sections -serialization-details std:label -1 usage/builders/index.html#$ Serialization builder details -setuptools std:label -1 usage/advanced/setuptools.html#$ Setuptools integration -show_authors std:confval 1 usage/configuration.html#confval-$ - -signatures std:label -1 usage/restructuredtext/domains.html#$ Python Signatures -singlehtml_sidebars std:confval 1 usage/configuration.html#confval-$ - -smartquotes std:confval 1 usage/configuration.html#confval-$ - -smartquotes_action std:confval 1 usage/configuration.html#confval-$ - -smartquotes_excludes std:confval 1 usage/configuration.html#confval-$ - -source directory std:term -1 glossary.html#term-source-directory - -source-dir std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -source-read std:event 1 extdev/appapi.html#event-$ - -source_encoding std:confval 1 usage/configuration.html#confval-$ - -source_parsers std:confval 1 usage/configuration.html#confval-$ - -source_suffix std:confval 1 usage/configuration.html#confval-$ - -sphinx-apidoc.--dry-run std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-n - -sphinx-apidoc.--follow-links std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-l - -sphinx-apidoc.--force std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-f - -sphinx-apidoc.--full std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-F - -sphinx-apidoc.--implicit-namespaces std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-implicit-namespaces - -sphinx-apidoc.--module-first std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-M - -sphinx-apidoc.--no-headings std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-E - -sphinx-apidoc.--no-toc std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-T - -sphinx-apidoc.--private std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-P - -sphinx-apidoc.--separate std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-e - -sphinx-apidoc.--templatedir std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-0 - -sphinx-apidoc.--tocfile std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-tocfile - -sphinx-apidoc.-A std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-A - -sphinx-apidoc.-E std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-E - -sphinx-apidoc.-F std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-F - -sphinx-apidoc.-H std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-H - -sphinx-apidoc.-M std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-M - -sphinx-apidoc.-P std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-P - -sphinx-apidoc.-R std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-R - -sphinx-apidoc.-T std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-T - -sphinx-apidoc.-V std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-V - -sphinx-apidoc.-a std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-a - -sphinx-apidoc.-d std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-d - -sphinx-apidoc.-e std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-e - -sphinx-apidoc.-f std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-f - -sphinx-apidoc.-l std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-l - -sphinx-apidoc.-n std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-n - -sphinx-apidoc.-o std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-o - -sphinx-apidoc.-q std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-q - -sphinx-apidoc.-s std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-s - -sphinx-apidoc.-t std:cmdoption 1 man/sphinx-apidoc.html#cmdoption-sphinx-apidoc-0 - -sphinx-autogen.--imported-members std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-i - -sphinx-autogen.--respect-module-all std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-a - -sphinx-autogen.--suffix std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-s - -sphinx-autogen.--templates std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-t - -sphinx-autogen.-a std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-a - -sphinx-autogen.-i std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-i - -sphinx-autogen.-o std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-o - -sphinx-autogen.-s std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-s - -sphinx-autogen.-t std:cmdoption 1 man/sphinx-autogen.html#cmdoption-sphinx-autogen-t - -sphinx-build.--help std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-h - -sphinx-build.--keep-going std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-keep-going - -sphinx-build.--version std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-h - -sphinx-build.-A std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-A - -sphinx-build.-C std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-C - -sphinx-build.-D std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-D - -sphinx-build.-E std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-E - -sphinx-build.-M std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-M - -sphinx-build.-N std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-N - -sphinx-build.-P std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-P - -sphinx-build.-Q std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-Q - -sphinx-build.-T std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-T - -sphinx-build.-W std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-W - -sphinx-build.-a std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-a - -sphinx-build.-b std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-b - -sphinx-build.-c std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-c - -sphinx-build.-d std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-d - -sphinx-build.-h std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-h - -sphinx-build.-j std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-j - -sphinx-build.-n std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-n - -sphinx-build.-q std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-q - -sphinx-build.-t std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-t - -sphinx-build.-v std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-v - -sphinx-build.-w std:cmdoption 1 man/sphinx-build.html#cmdoption-sphinx-build-w - -sphinx-quickstart.--author std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-a - -sphinx-quickstart.--batchfile std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-batchfile - -sphinx-quickstart.--dot std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-dot - -sphinx-quickstart.--ext-autodoc std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-autodoc - -sphinx-quickstart.--ext-coverage std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-coverage - -sphinx-quickstart.--ext-doctest std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-doctest - -sphinx-quickstart.--ext-githubpages std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-githubpages - -sphinx-quickstart.--ext-ifconfig std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-ifconfig - -sphinx-quickstart.--ext-imgmath std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-imgmath - -sphinx-quickstart.--ext-intersphinx std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-intersphinx - -sphinx-quickstart.--ext-mathjax std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-mathjax - -sphinx-quickstart.--ext-todo std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-todo - -sphinx-quickstart.--ext-viewcode std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-ext-viewcode - -sphinx-quickstart.--extensions std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-extensions - -sphinx-quickstart.--help std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-h - -sphinx-quickstart.--language std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-l - -sphinx-quickstart.--makefile std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-makefile - -sphinx-quickstart.--master std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-master - -sphinx-quickstart.--no-batchfile std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-batchfile - -sphinx-quickstart.--no-makefile std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-makefile - -sphinx-quickstart.--no-sep std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-no-sep - -sphinx-quickstart.--no-use-make-mode std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-use-make-mode - -sphinx-quickstart.--project std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-p - -sphinx-quickstart.--quiet std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-q - -sphinx-quickstart.--release std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-r - -sphinx-quickstart.--sep std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-sep - -sphinx-quickstart.--suffix std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-suffix - -sphinx-quickstart.--templatedir std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-t - -sphinx-quickstart.--use-make-mode std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-use-make-mode - -sphinx-quickstart.--version std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-h - -sphinx-quickstart.-a std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-a - -sphinx-quickstart.-d std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-d - -sphinx-quickstart.-h std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-h - -sphinx-quickstart.-l std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-l - -sphinx-quickstart.-p std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-p - -sphinx-quickstart.-q std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-q - -sphinx-quickstart.-r std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-r - -sphinx-quickstart.-t std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-t - -sphinx-quickstart.-v std:cmdoption 1 man/sphinx-quickstart.html#cmdoption-sphinx-quickstart-v - -sphinx.ext.imgconverter std:label -1 usage/extensions/imgconverter.html#sphinx-ext-imgconverter sphinx.ext.imgconverter – A reference image converter using Imagemagick -storagebackends std:label -1 usage/advanced/websupport/storagebackends.html#$ Storage Backends -strip_signature_backslash std:confval 1 usage/configuration.html#confval-$ - -support std:doc -1 support.html Get support -suppress_warnings std:confval 1 usage/configuration.html#confval-$ - -table-directives std:label -1 usage/restructuredtext/directives.html#$ Tables -tablecolors std:label -1 latex.html#$ TableRowColorHeader -tags std:label -1 usage/restructuredtext/directives.html#$ Including content based on tags -template-bridge std:label -1 extdev/appapi.html#$ The template bridge -template_bridge std:confval 1 usage/configuration.html#confval-$ - -templates_path std:confval 1 usage/configuration.html#confval-$ - -templating std:doc -1 templating.html Templating -templating std:label -1 templating.html#$ Templating -texinfo-faq std:label -1 faq.html#$ Texinfo info -texinfo-links std:label -1 faq.html#$ Displaying Links -texinfo-options std:label -1 usage/configuration.html#$ Options for Texinfo output -texinfo_appendices std:confval 1 usage/configuration.html#confval-$ - -texinfo_cross_references std:confval 1 usage/configuration.html#confval-$ - -texinfo_documents std:confval 1 usage/configuration.html#confval-$ - -texinfo_domain_indices std:confval 1 usage/configuration.html#confval-$ - -texinfo_elements std:confval 1 usage/configuration.html#confval-$ - -texinfo_no_detailmenu std:confval 1 usage/configuration.html#confval-$ - -texinfo_show_urls std:confval 1 usage/configuration.html#confval-$ - -text-options std:label -1 usage/configuration.html#$ Options for text output -text_add_secnumbers std:confval 1 usage/configuration.html#confval-$ - -text_newlines std:confval 1 usage/configuration.html#confval-$ - -text_secnumber_suffix std:confval 1 usage/configuration.html#confval-$ - -text_sectionchars std:confval 1 usage/configuration.html#confval-$ - -theming-static-templates std:label -1 development/theming.html#$ Static templates -third-party-extensions std:label -1 usage/extensions/index.html#$ Third-party extensions -third-party-themes std:label -1 usage/theming.html#$ Third Party Themes -tls_cacerts std:confval 1 usage/configuration.html#confval-$ - -tls_verify std:confval 1 usage/configuration.html#confval-$ - -toc_object_entries std:confval 1 usage/configuration.html#confval-$ - -toc_object_entries_show_parents std:confval 1 usage/configuration.html#confval-$ - -toctree-directive std:label -1 usage/restructuredtext/directives.html#$ Table of contents -today std:confval 1 usage/configuration.html#confval-$ - -today std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -today_fmt std:confval 1 usage/configuration.html#confval-$ - -todo-defined std:event 1 usage/extensions/todo.html#event-$ - -todo_emit_warnings std:confval 1 usage/extensions/todo.html#confval-$ - -todo_include_todos std:confval 1 usage/extensions/todo.html#confval-$ - -todo_link_only std:confval 1 usage/extensions/todo.html#confval-$ - -trim_doctest_flags std:confval 1 usage/configuration.html#confval-$ - -trim_footnote_reference_space std:confval 1 usage/configuration.html#confval-$ - -tutorial std:label -1 tutorial/index.html#$ Tutorial: Build your first project -tutorial-describing-objects std:label -1 tutorial/describing-code.html#$ Python -tutorial/automatic-doc-generation std:doc -1 tutorial/automatic-doc-generation.html Automatic documentation generation from code -tutorial/deploying std:doc -1 tutorial/deploying.html Appendix: Deploying a Sphinx project online -tutorial/describing-code std:doc -1 tutorial/describing-code.html Describing code in Sphinx -tutorial/end std:doc -1 tutorial/end.html Where to go from here -tutorial/first-steps std:doc -1 tutorial/first-steps.html First steps to document your project using Sphinx -tutorial/getting-started std:doc -1 tutorial/getting-started.html Getting started -tutorial/index std:doc -1 tutorial/index.html Tutorial: Build your first project -tutorial/more-sphinx-customization std:doc -1 tutorial/more-sphinx-customization.html More Sphinx customization -tutorial/narrative-documentation std:doc -1 tutorial/narrative-documentation.html Narrative documentation in Sphinx -type std:label -1 usage/configuration.html#$ - -usage/advanced/intl std:doc -1 usage/advanced/intl.html Internationalization -usage/advanced/setuptools std:doc -1 usage/advanced/setuptools.html Setuptools integration -usage/advanced/websupport/api std:doc -1 usage/advanced/websupport/api.html The WebSupport Class -usage/advanced/websupport/index std:doc -1 usage/advanced/websupport/index.html Sphinx Web Support -usage/advanced/websupport/quickstart std:doc -1 usage/advanced/websupport/quickstart.html Web Support Quick Start -usage/advanced/websupport/searchadapters std:doc -1 usage/advanced/websupport/searchadapters.html Search Adapters -usage/advanced/websupport/storagebackends std:doc -1 usage/advanced/websupport/storagebackends.html Storage Backends -usage/builders/index std:doc -1 usage/builders/index.html Builders -usage/configuration std:doc -1 usage/configuration.html Configuration -usage/extensions/autodoc std:doc -1 usage/extensions/autodoc.html sphinx.ext.autodoc – Include documentation from docstrings -usage/extensions/autosectionlabel std:doc -1 usage/extensions/autosectionlabel.html sphinx.ext.autosectionlabel – Allow reference sections using its title -usage/extensions/autosummary std:doc -1 usage/extensions/autosummary.html sphinx.ext.autosummary – Generate autodoc summaries -usage/extensions/coverage std:doc -1 usage/extensions/coverage.html sphinx.ext.coverage – Collect doc coverage stats -usage/extensions/doctest std:doc -1 usage/extensions/doctest.html sphinx.ext.doctest – Test snippets in the documentation -usage/extensions/duration std:doc -1 usage/extensions/duration.html sphinx.ext.duration – Measure durations of Sphinx processing -usage/extensions/example_google std:doc -1 usage/extensions/example_google.html Example Google Style Python Docstrings -usage/extensions/example_numpy std:doc -1 usage/extensions/example_numpy.html Example NumPy Style Python Docstrings -usage/extensions/extlinks std:doc -1 usage/extensions/extlinks.html sphinx.ext.extlinks – Markup to shorten external links -usage/extensions/githubpages std:doc -1 usage/extensions/githubpages.html sphinx.ext.githubpages – Publish HTML docs in GitHub Pages -usage/extensions/graphviz std:doc -1 usage/extensions/graphviz.html sphinx.ext.graphviz – Add Graphviz graphs -usage/extensions/ifconfig std:doc -1 usage/extensions/ifconfig.html sphinx.ext.ifconfig – Include content based on configuration -usage/extensions/imgconverter std:doc -1 usage/extensions/imgconverter.html sphinx.ext.imgconverter – A reference image converter using Imagemagick -usage/extensions/index std:doc -1 usage/extensions/index.html Extensions -usage/extensions/inheritance std:doc -1 usage/extensions/inheritance.html sphinx.ext.inheritance_diagram – Include inheritance diagrams -usage/extensions/intersphinx std:doc -1 usage/extensions/intersphinx.html sphinx.ext.intersphinx – Link to other projects’ documentation -usage/extensions/linkcode std:doc -1 usage/extensions/linkcode.html sphinx.ext.linkcode – Add external links to source code -usage/extensions/math std:doc -1 usage/extensions/math.html Math support for HTML outputs in Sphinx -usage/extensions/napoleon std:doc -1 usage/extensions/napoleon.html sphinx.ext.napoleon – Support for NumPy and Google style docstrings -usage/extensions/todo std:doc -1 usage/extensions/todo.html sphinx.ext.todo – Support for todo items -usage/extensions/viewcode std:doc -1 usage/extensions/viewcode.html sphinx.ext.viewcode – Add links to highlighted source code -usage/index std:doc -1 usage/index.html Using Sphinx -usage/installation std:doc -1 usage/installation.html Installing Sphinx -usage/markdown std:doc -1 usage/markdown.html Markdown -usage/quickstart std:doc -1 usage/quickstart.html Getting Started -usage/restructuredtext/basics std:doc -1 usage/restructuredtext/basics.html reStructuredText Primer -usage/restructuredtext/directives std:doc -1 usage/restructuredtext/directives.html Directives -usage/restructuredtext/domains std:doc -1 usage/restructuredtext/domains.html Domains -usage/restructuredtext/field-lists std:doc -1 usage/restructuredtext/field-lists.html Field Lists -usage/restructuredtext/index std:doc -1 usage/restructuredtext/index.html reStructuredText -usage/restructuredtext/roles std:doc -1 usage/restructuredtext/roles.html Roles -usage/theming std:doc -1 usage/theming.html HTML Theming -user-guides std:label -1 index.html#$ User Guides -user_agent std:confval 1 usage/configuration.html#confval-$ - -user_dic option std:label -1 usage/configuration.html#user-dic-option - -user_dic_enc option std:label -1 usage/configuration.html#user-dic-enc-option - -usingwith std:label -1 faq.html#$ Using Sphinx with… -version std:confval 1 usage/configuration.html#confval-$ - -version std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -viewcode-find-source std:event 1 usage/extensions/viewcode.html#event-$ - -viewcode-follow-imported std:event 1 usage/extensions/viewcode.html#event-$ - -viewcode_enable_epub std:confval 1 usage/extensions/viewcode.html#confval-$ - -viewcode_follow_imported_members std:confval 1 usage/extensions/viewcode.html#confval-$ - -warn-missing-reference std:event 1 extdev/appapi.html#event-$ - -warning-is-error std:setuptools-confval 1 usage/advanced/setuptools.html#setuptools-confval-$ - -websupport std:label -1 usage/advanced/websupport/index.html#$ Sphinx Web Support -websupportapi std:label -1 usage/advanced/websupport/api.html#$ The WebSupport Class -websupportquickstart std:label -1 usage/advanced/websupport/quickstart.html#$ Web Support Quick Start -when-deprecation-warnings-are-displayed std:label -1 man/sphinx-build.html#$ Deprecation Warnings -windows-other-method std:label -1 usage/installation.html#$ Other Methods -writing-builders std:label -1 extdev/builderapi.html#$ Builder API -xml_pretty std:confval 1 usage/configuration.html#confval-$ - -xref-syntax std:label -1 usage/restructuredtext/roles.html#$ Cross-referencing syntax diff --git a/tests/test_api_good.py b/tests/test_api_good.py index 540802cc..70f1d185 100644 --- a/tests/test_api_good.py +++ b/tests/test_api_good.py @@ -576,6 +576,9 @@ def test_api_inventory_matches_sphinx_ifile( # TODO: Refine this adjustment as a function of sphinx_version if needed assert inv.count == 13 + sphinx_ifile_data_count(original_ifile_data), fname + elif "sphinx.inv" in fname: # pragma: no cover + assert inv.count == 4 + sphinx_ifile_data_count(original_ifile_data), fname + else: assert inv.count == sphinx_ifile_data_count(original_ifile_data), fname diff --git a/tests/test_valid_objects.py b/tests/test_valid_objects.py index 5e3930cd..ce88c18e 100644 --- a/tests/test_valid_objects.py +++ b/tests/test_valid_objects.py @@ -69,12 +69,15 @@ def skip_on_sphinx_version(sphinx_version): ("Index # Page", "std", "doc", 1, "index.html", "-"), # Symbol in name ("Thing \u33a4", "std", "ref", 1, "index.html#$", "-"), # Unicode in name ("Thing One", "std", "ref", 1, "index.html#$", "\u33a4"), # Unicode in dispname + ("foo", "py", "da:ta", 1, "data.html#$", "-"), # Colon in role (used in Sphinx) ("foo", "py$", "data", 1, "data.html#$", "-"), # Valid but discouraged ("foo", "py\u33a4", "data", 1, "data.html#$", "-"), # Valid but discouraged ("foo", "py", "data$", 1, "data.html#$", "-"), # Valid but discouraged ("foo", "py", "data\u33a4", 1, "data.html#$", "-"), # Valid but discouraged ("foo", "py", "data", 1, "data/\u33a4.html#$", "-"), # Valid but discouraged (" foo", "py", "data", 1, "data.html#$", "-"), # Valid but discouraged + # Colon in domain (invalid but undetectable) + ("foo", "p:y", "data", 1, "data.html#$", "-"), ], ) def test_dataobjstr_valid_objects( @@ -123,10 +126,8 @@ def test_dataobjstr_valid_objects( ("foo ", "py", "data", 1, "data.html#$", "-"), # Name w/trailing space ("# Index Page", "std", "doc", 1, "index.html", "-"), # '#' @ name start ("X Y Z 0 foo", "std", "doc", 1, "index.html", "-"), # Int in name - ("foo", "p:y", "data", 1, "data.html#$", "-"), # Colon in domain ("foo", "py thon", "data", 1, "data.html#$", "-"), # Space in domain ("foo", "", "data", 1, "data.html#$", "-"), # Missing domain - ("foo", "py", "da:ta", 1, "data.html#$", "-"), # Colon in role ("foo", "py", "da ta", 1, "data.html#$", "-"), # Space in role ("foo", "py", "", 1, "data.html#$", "-"), # Missing role ("foo", "py", "data", 0.5, "data.html#$", "-"), # Non-integer prio From ce8cb2a0c56cc71a279b5b137c0f2097562604b9 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 3 Nov 2022 19:20:13 -0400 Subject: [PATCH 076/106] Update doctests --- doc/source/api_usage.rst | 51 +++++++++++++++++++------------------- doc/source/cli/convert.rst | 20 +++++++-------- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/doc/source/api_usage.rst b/doc/source/api_usage.rst index 20d8b556..8e6e097c 100644 --- a/doc/source/api_usage.rst +++ b/doc/source/api_usage.rst @@ -17,11 +17,11 @@ Inspecting the contents of an existing inventory is handled entirely by the >>> inv = soi.Inventory('objects_attrs.inv') >>> print(inv) - + >>> inv.version - '17.2' + '22.1' >>> inv.count - 56 + 129 The location of the inventory file to import can also be provided as a :class:`pathlib.Path`, instead of as a string: @@ -38,12 +38,12 @@ a |list| in the :attr:`~sphobjinv.inventory.Inventory.objects` attribute: .. doctest:: api_inspect >>> len(inv.objects) - 56 + 129 >>> dobj = inv.objects[0] >>> dobj - DataObjStr(name='attr.Attribute', domain='py', role='class', priority='1', uri='api.html#$', dispname='-') + DataObjStr(name='attr', domain='py', role='module', priority='0', uri='index.html#module-$', dispname='-') >>> dobj.name - 'attr.Attribute' + 'attr' >>> dobj.domain 'py' >>> [d.name for d in inv.objects if 'validator' in d.uri] @@ -56,10 +56,10 @@ inventories, as |bytes|: >>> inv2 = soi.Inventory(inv.data_file()) >>> print(inv2) - + >>> inv3 = soi.Inventory(soi.compress(inv.data_file())) >>> print(inv3) - + Remote |objects.inv| files can also be retrieved via URL, with the *url* keyword argument: @@ -67,7 +67,7 @@ Remote |objects.inv| files can also be retrieved via URL, with the *url* keyword >>> inv4 = soi.Inventory(url='https://github.com/bskinn/sphobjinv/raw/main/tests/resource/objects_attrs.inv') >>> print(inv4) - + Comparing Inventories --------------------- @@ -118,10 +118,10 @@ The :class:`~sphobjinv.data.DataObjStr` instances can be edited in place: >>> inv = soi.Inventory('objects_attrs.inv') >>> inv.objects[0] - DataObjStr(name='attr.Attribute', domain='py', role='class', priority='1', uri='api.html#$', dispname='-') + DataObjStr(name='attr', domain='py', role='module', priority='0', uri='index.html#module-$', dispname='-') >>> inv.objects[0].uri = 'attribute.html' >>> inv.objects[0] - DataObjStr(name='attr.Attribute', domain='py', role='class', priority='1', uri='attribute.html', dispname='-') + DataObjStr(name='attr', domain='py', role='module', priority='0', uri='attribute.html', dispname='-') New instances can be easily created either by direct instantiation, or by :meth:`~sphobjinv.data.SuperDataObj.evolve`: @@ -130,9 +130,9 @@ New instances can be easily created either by direct instantiation, or by >>> inv.objects.append(inv.objects[0].evolve(name='attr.Generator', uri='generator.html')) >>> inv.count - 57 + 130 >>> inv.objects[-1] - DataObjStr(name='attr.Generator', domain='py', role='class', priority='1', uri='generator.html', dispname='-') + DataObjStr(name='attr.Generator', domain='py', role='module', priority='0', uri='generator.html', dispname='-') The other attributes of the :class:`~sphobjinv.inventory.Inventory` instance can also be freely modified: @@ -141,7 +141,7 @@ The other attributes of the :class:`~sphobjinv.inventory.Inventory` instance can >>> inv.project = 'not_attrs' >>> inv.version = '0.1' >>> print(inv) - + Formatting Inventory Contents @@ -156,10 +156,10 @@ the plaintext |objects.inv| format **as** |bytes| via :meth:`~sphobjinv.inventor >>> print(*inv.data_file().splitlines()[:6], sep='\n') b'# Sphinx inventory version 2' b'# Project: attrs' - b'# Version: 17.2' + b'# Version: 22.1' b'# The remainder of this file is compressed using zlib.' - b'attr.Attribute py:class 1 api.html#$ -' - b'attr.Factory py:class 1 api.html#$ -' + b'attr py:module 0 index.html#module-$ -' + b'attr.VersionInfo py:class 1 api.html#$ -' This method makes use of the :meth:`DataObjStr.data_line ` method to format each of the object information lines. @@ -171,11 +171,11 @@ If desired, the :ref:`shorthand ` used for the .. doctest:: api_formatting >>> print(*inv.data_file(expand=True).splitlines()[4:6], sep='\n') - b'attr.Attribute py:class 1 api.html#attr.Attribute attr.Attribute' - b'attr.Factory py:class 1 api.html#attr.Factory attr.Factory' + b'attr py:module 0 index.html#module-attr attr' + b'attr.VersionInfo py:class 1 api.html#attr.VersionInfo attr.VersionInfo' >>> do = inv.objects[0] >>> do.data_line(expand=True) - 'attr.Attribute py:class 1 api.html#attr.Attribute attr.Attribute' + 'attr py:module 0 index.html#module-attr attr' Exporting an Inventory @@ -202,10 +202,10 @@ To export plaintext: >>> print(*Path('objects_attrs.txt').read_text().splitlines()[:6], sep='\n') # Sphinx inventory version 2 # Project: attrs - # Version: 17.2 + # Version: 22.1 # The remainder of this file is compressed using zlib. - attr.Attribute py:class 1 api.html#$ - - attr.Factory py:class 1 api.html#$ - + attr py:module 0 index.html#module-$ - + attr.VersionInfo py:class 1 api.html#$ - For zlib-compressed: @@ -216,10 +216,10 @@ For zlib-compressed: >>> print(*Path('objects_attrs_new.inv').read_bytes().splitlines()[:4], sep='\n') b'# Sphinx inventory version 2' b'# Project: attrs' - b'# Version: 17.2' + b'# Version: 22.1' b'# The remainder of this file is compressed using zlib.' >>> print(Path('objects_attrs_new.inv').read_bytes().splitlines()[6][:10]) - b'5\xcb0\xd7\x9f>\xf3\x84\x89' + b'\xbf\x86\x8fL49\xc4\x91\xb8\x8c' For JSON: @@ -229,4 +229,3 @@ For JSON: >>> soi.writejson('objects_attrs.json', jd) >>> print(Path('objects_attrs.json').read_text()[:51]) # doctest: +SKIP {"project": "attrs", "version": "17.2", "count": 56 - diff --git a/doc/source/cli/convert.rst b/doc/source/cli/convert.rst index 5b91342d..b979fc78 100644 --- a/doc/source/cli/convert.rst +++ b/doc/source/cli/convert.rst @@ -32,10 +32,10 @@ Basic file conversion to the default output filename is straightforward: >>> print(file_head('objects_attrs.txt', head=6)) # Sphinx inventory version 2 # Project: attrs - # Version: 17.2 + # Version: 22.1 # The remainder of this file is compressed using zlib. - attr.Attribute py:class 1 api.html#$ - - attr.Factory py:class 1 api.html#$ - + attr py:module 0 index.html#module-$ - + attr.VersionInfo py:class 1 api.html#$ - A different target filename can be specified, to avoid overwriting an existing file: @@ -76,10 +76,10 @@ indicated URL): >>> print(file_head('objects.txt', head=6)) # Sphinx inventory version 2 # Project: attrs - # Version: 17.2 + # Version: 22.1 # The remainder of this file is compressed using zlib. - attr.Attribute py:class 1 api.html#$ - - attr.Factory py:class 1 api.html#$ - + attr py:module 0 index.html#module-$ - + attr.VersionInfo py:class 1 api.html#$ - The URL provided **MUST** have the leading protocol specified (here, |cour|\ https\ ://\ |/cour|). @@ -135,11 +135,11 @@ If processing of JSON files by API URL is desirable, please >>> cli_run('sphobjinv co plain objects_attrs.inv -') # Sphinx inventory version 2 # Project: attrs - # Version: 17.2 + # Version: 22.1 # The remainder of this file is compressed using zlib. - attr.Attribute py:class 1 api.html#$ - - attr.Factory py:class 1 api.html#$ - - attr.asdict py:function 1 api.html#$ - + attr py:module 0 index.html#module-$ - + attr.VersionInfo py:class 1 api.html#$ - + attr._make.Attribute py:class -1 api.html#attrs.Attribute - ... From 157a60fcaed80ebd8d0bf44de7dd6b4363ac6f7a Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 3 Nov 2022 19:55:26 -0400 Subject: [PATCH 077/106] Add CHANGELOG entry. Closes #256. --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 456aed9d..1980872c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,20 +26,48 @@ and this project strives to adhere to #### Fixed + * The regex for parsing object lines from decompressed inventories now + correctly processes `{role}` values that contain internal colons. + * CLI corner case where options are passed but no subparser is specified now results in a clean error-exit, instead of an exception. ([#239](https://github.com/bskinn/sphobjinv/issues/239)) #### Documentation - * Add new 'CLI implementation' pages for the new modules, downstream of the + * Updated doctests to reflect the new v22.1 attrs `objects.inv` used for + demonstration purposes. + + * Updated `syntax.rst` to indicate that the `{role}` in an inventory object + MAY contain a colon. + + * Added new 'CLI implementation' pages for the new modules, downstream of the refactoring of the CLI 'convert' and 'suggest' code. - * Revise the intro paragraph of the 'CLI usage' page to more clearly emphasize + * Revised the intro paragraph of the 'CLI usage' page to more clearly emphasize the two CLI subcommands and the links to their respective docs pages. * Fixed a mistake in the CLI help info for the `--url` argument to `convert`. +#### Tests + + * Various tests were updated to reflect the contents of the new v22.1 attrs + `objects.inv` introduced to replace the previous v17.2 inventory. + + * A modern Sphinx `objects.inv` (v6.0.0b) was added to `tests/resource` as + `objects_sphinx.inv`, and the previous v1.6.6 was renamed to + `objects_sphinx_1_6_6.inv`. + + * The 'valid objects' test cases were updated to reflect the possibility for a colon within `{role}`: + + * The colon-within-`{role}` test case was moved from 'invalid' to 'valid'. + + * The colon-within-`{domain}` test case was also moved from 'invalid' to + 'valid', but with an annotation added to indicate that it's not actually + viable---it will actually be interpreted incorrectly, with the first + portion of the colon-containing `{domain}` imported as `{domain}`, and the + remainder imported as part of `{role}`. + #### Internal * Refactor CLI code to place the 'convert' and 'suggest' implementations in From 1e62595d9229b42a253a181acde73284165538cb Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Thu, 3 Nov 2022 23:32:24 -0400 Subject: [PATCH 078/106] Update refs to Sphinx docs Freshened links, updated some text, updated the screenshot showing a mouseover title. --- doc/source/_static/mouseover_example.png | Bin 13714 -> 48977 bytes doc/source/customfile.rst | 8 +++---- doc/source/index.rst | 2 +- doc/source/syntax.rst | 29 +++++++++++++---------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/doc/source/_static/mouseover_example.png b/doc/source/_static/mouseover_example.png index 07e60cba1fb76d429d77a51a433aa06d904daffe..eef34b44b1ea27405ffc3e8b61f4e2509e786483 100644 GIT binary patch literal 48977 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 St3llW0000%y@cU2A&eTrr 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, + domains `__, and not the abbreviated forms ("`inline directives`") `used when constructing cross-references - `__. + `__. Thus, for example, a :class:`~sphobjinv.data.DataObjStr` corresponding to a method on a class should be constructed with @@ -148,8 +148,8 @@ can be found at the GitHub repo # Django puts its objects.inv file in a non-standard location 'django': ('https://docs.djangoproject.com/en/dev/', 'https://docs.djangoproject.com/en/dev/_objects/'), - # Drawing the Sphinx objects.inv from a local copy, but referring to the 1.7 web docs - 'sphinx': ('https://www.sphinx-doc.org/en/1.7/', '/path/to/local/objects.inv'), + # Drawing the Sphinx objects.inv from a local copy, but referring to the current web docs + 'sphinx': ('https://www.sphinx-doc.org/en/master/', '/path/to/local/objects.inv'), } .. MAKE SURE TO UPDATE THESE TWO STEP REFERENCES IF NUMBERING CHANGES!! diff --git a/doc/source/index.rst b/doc/source/index.rst index 488bd638..a77bf227 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -11,7 +11,7 @@ Welcome to sphobjinv! When documentation is built using, e.g., Sphinx's :obj:`~sphinx.builders.html.StandaloneHTMLBuilder`, an inventory of the named objects in the documentation set `is dumped -`__ +`__ to a file called |objects.inv| in the html build directory. (One common location is, |cour|\ doc/build/html\ |/cour|, though the exact location will vary depending on the details of how Sphinx is configured.) This file is read by |isphx| when diff --git a/doc/source/syntax.rst b/doc/source/syntax.rst index a89e2614..f3bd1c53 100644 --- a/doc/source/syntax.rst +++ b/doc/source/syntax.rst @@ -3,10 +3,11 @@ Sphinx objects.inv v2 Syntax ============================ -After decompression, "version 2" Sphinx |objects.inv| files -follow a syntax that, to the best of this author's ability to determine, -is not included in the Sphinx documentation. The below -syntax is believed to be accurate as of Jan 2022 (Sphinx v4.4.0). +After decompression, "version 2" Sphinx |objects.inv| files follow a syntax +that, to the best of this author's ability to determine, is not included in the +Sphinx documentation. The below syntax is believed to be accurate as of Nov 2022 +(Sphinx v6.0.0b2). It is based on inspection of |objects.inv| files "in the +wild" and of the Sphinx inventory object `parsing regex`_. Based upon a quick ``git diff`` of the `Sphinx repository `__, it is thought to be valid for all @@ -22,7 +23,7 @@ of an |objects.inv| data line. ---- **The first line** `must be exactly -`__: +`__: .. code-block:: none @@ -31,7 +32,7 @@ of an |objects.inv| data line. ---- **The second and third lines** `must obey -`__ +`__ the template: .. code-block:: none @@ -51,7 +52,7 @@ the |isphx| cross-references: ---- **The fourth line** `must contain -`__ +`__ the string ``zlib`` somewhere within it, but for consistency it should be exactly: .. code-block:: none @@ -62,7 +63,7 @@ the string ``zlib`` somewhere within it, but for consistency it should be exactl **All remaining lines** of the file are the objects data, each laid out in the `following syntax -`__: +`__: .. code-block:: none @@ -127,7 +128,7 @@ the string ``zlib`` somewhere within it, but for consistency it should be exactl ``{priority}`` Flag for `placement in search results - `__. Most will be ``1`` (standard priority) or + `__. Most will be ``1`` (standard priority) or ``-1`` (omit from results) for documentation built by Sphinx. To note, as of Jan 2022 this value is **not** used by ``intersphinx``; @@ -211,11 +212,11 @@ size of the inventory file: `__," the portion following the ``#`` symbol) and the tail of the anchor is identical to |{name}|_, that tail is `replaced - `__ + `__ with ``$``. |br| |br| #. If |{dispname}|_ is identical to |{name}|_, it is `stored - `__ + `__ as ``-``. Thus, a standard |isphx| reference to this method would take the form: @@ -265,11 +266,11 @@ as in :obj:`This is join! `: .. |prio_js_search| replace:: here -.. _prio_js_search: https://github.com/sphinx-doc/sphinx/blob/241577f65eea94a08944bf096bd704b495282373/sphinx/themes/basic/static/searchtools.js#L26-L43 +.. _prio_js_search: https://github.com/sphinx-doc/sphinx/blob/2f60b44999d7e610d932529784f082fc1c6af989/sphinx/themes/basic/static/searchtools.js#L28-L47 .. |prio_py_search| replace:: here -.. _prio_py_search: https://github.com/sphinx-doc/sphinx/blob/241577f65eea94a08944bf096bd704b495282373/sphinx/search/__init__.py#L332 +.. _prio_py_search: https://github.com/sphinx-doc/sphinx/blob/2f60b44999d7e610d932529784f082fc1c6af989/sphinx/search/__init__.py#L332-L333 .. |sphinx_uri_issue| replace:: sphinx-doc/sphinx#7096 @@ -290,3 +291,5 @@ as in :obj:`This is join! `: .. |rst-directive-option| replace:: ``:rst:directive:option:`` .. _rst-directive-option: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-rst-directive-option + +.. _parsing regex: https://github.com/sphinx-doc/sphinx/blob/2f60b44999d7e610d932529784f082fc1c6af989/sphinx/util/inventory.py#L115-L116 From 59035f6167689d63c073a5cc96bc7f2473ef01c2 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Fri, 4 Nov 2022 23:41:05 -0400 Subject: [PATCH 079/106] Add proj/ver print to suggest; update tests/docs Closes #257. --- CHANGELOG.md | 3 +++ README.rst | 21 ++++++++++++++------- doc/source/cli/suggest.rst | 2 +- src/sphobjinv/cli/suggest.py | 3 +++ 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1980872c..f4033f56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project strives to adhere to #### Added + * The CLI now prints the project name and version for the `objects.inv` as + part of the 'suggest' mode output. + * The CLI now prints an inferred `intersphinx_mapping` entry for a remote docset as part of the 'suggest' mode output, where such inference is possible. The output from this mapping inference was added to the relevant diff --git a/README.rst b/README.rst index 929dd06d..4dbdec7c 100644 --- a/README.rst +++ b/README.rst @@ -57,6 +57,9 @@ For internal cross-references, locate ``objects.inv`` within ``build/html``:: $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 + Project: sphobjinv + Version: 2.3 + 219 objects in inventory. 11 results found at/above current threshold of 58. @@ -89,24 +92,28 @@ with the ``--url/-u`` flag. For example, say I need to know how to cross-reference the ``linspace`` function from numpy (see `here `__):: - $ sphobjinv suggest https://numpy.org/doc/1.19/reference/index.html linspace -su + $ sphobjinv suggest https://numpy.org/doc/1.23/reference/index.html linspace -su - Attempting https://numpy.org/doc/1.19/reference/index.html ... + Attempting https://numpy.org/doc/1.23/reference/index.html ... ... no recognized inventory. - Attempting "https://numpy.org/doc/1.19/reference/index.html/objects.inv" ... + Attempting "https://numpy.org/doc/1.23/reference/index.html/objects.inv" ... ... HTTP error: 404 Not Found. - Attempting "https://numpy.org/doc/1.19/reference/objects.inv" ... + Attempting "https://numpy.org/doc/1.23/reference/objects.inv" ... ... HTTP error: 404 Not Found. - Attempting "https://numpy.org/doc/1.19/objects.inv" ... + Attempting "https://numpy.org/doc/1.23/objects.inv" ... ... inventory found. - 6487 objects in inventory. + Project: NumPy + Version: 1.23 + + 8074 objects in inventory. 8 results found at/above current threshold of 75. The intersphinx_mapping for this docset is LIKELY: - (https://numpy.org/doc/1.19/, None) + (https://numpy.org/doc/1.23/, None) + Name Score -------------------------------------------------------------- ------- diff --git a/doc/source/cli/suggest.rst b/doc/source/cli/suggest.rst index 26cfc967..21fa0a29 100644 --- a/doc/source/cli/suggest.rst +++ b/doc/source/cli/suggest.rst @@ -39,7 +39,7 @@ It is usually not necessary to locate the |objects.inv| file before running |soi for most Sphinx documentation sets, if you provide a URL to any page in the docs, it will automatically find and use the correct |objects.inv|: -.. command-output:: sphobjinv suggest -u https://sphobjinv.readthedocs.io/en/v2.0/cli/convert.html compress +.. command-output:: sphobjinv suggest -u https://sphobjinv.readthedocs.io/en/stable/cli/convert.html compress :cwd: /../../tests/resource |soi| only supports download of zlib-compressed |objects.inv| files by URL. diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 1be2c3db..80d41cea 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -74,6 +74,9 @@ def do_suggest(inv, params): with_score=with_score, ) + print_stderr(f"Project: {inv.project}", params) + print_stderr(f"Version: {inv.version}\n", params) + print_stderr(f"{inv.count} objects in inventory.\n", params) print_stderr_result_count(params, results) From 90fffffd108af95beb7f94c60e32c5e15d2bad65 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 5 Nov 2022 07:58:18 -0400 Subject: [PATCH 080/106] Remove (temporarily?) broken Alpine pkg link --- doc/source/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/index.rst b/doc/source/index.rst index a77bf227..e93c911f 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -49,7 +49,7 @@ Alternatively, |soi| is packaged with `multiple POSIX distributions `__ and package managers, including: - * Alpine Linux: ``py3-sphobjinv`` (`info `__) + * Alpine Linux: ``py3-sphobjinv`` * Arch Linux: ``python-sphobjinv`` (`info `__) From 7e96dfe0e388ca4489d2faefdebafb1eb3fcfa60 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Wed, 2 Nov 2022 23:11:34 -0400 Subject: [PATCH 081/106] Fix Django objects count for Sphinx ifile For Sphinx < 3.3, all objects imported. For >=3.3, several no longer import cleanly. --- tests/test_api_good.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_api_good.py b/tests/test_api_good.py index 70f1d185..877d3763 100644 --- a/tests/test_api_good.py +++ b/tests/test_api_good.py @@ -573,8 +573,13 @@ def test_api_inventory_matches_sphinx_ifile( ), fname elif "django.inv" in fname: # pragma: no cover - # TODO: Refine this adjustment as a function of sphinx_version if needed - assert inv.count == 13 + sphinx_ifile_data_count(original_ifile_data), fname + # 13 objects misbehave on import for Sphinx >= 3.3.0 + if sphinx_version < (3, 3, 0): + assert inv.count == sphinx_ifile_data_count(original_ifile_data), fname + else: + assert inv.count == 13 + sphinx_ifile_data_count( + original_ifile_data + ), fname elif "sphinx.inv" in fname: # pragma: no cover assert inv.count == 4 + sphinx_ifile_data_count(original_ifile_data), fname From dcd0ccf4c35f6dbad4f139a1e8cf2c8b6fe7cff3 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Wed, 2 Nov 2022 23:12:28 -0400 Subject: [PATCH 082/106] Add some comments to tox.ini Mainly explaining the environment matrix --- tox.ini | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 6ff6b857..13d861b1 100644 --- a/tox.ini +++ b/tox.ini @@ -2,21 +2,35 @@ minversion=2.0 isolated_build=True envlist= + # Test all Python versions on latest lib versions py3{6,7,8,9,10,11}-sphx_latest-attrs_latest-jsch_latest + # Test dev Python version on current in-repo dev lib versions py310-sphx_dev-attrs_dev-jsch_dev - py310-sphx_{1_6_x,1_x,2_x,3_x,4_x,dev}-attrs_latest-jsch_latest + # Scan across Sphinx versions + py310-sphx_{1_6_x,1_x,2_x,4_x,dev}-attrs_latest-jsch_latest + # sphx_3_x is incompatible with py310 due to a typing import. Test on py39 instead. + py39-sphx_3_x-attrs_latest-jsch_latest + # Scan attrs versions py310-sphx_latest-attrs_{19_2,19_3,20_1,20_2,20_3,21_2,21_3,dev}-jsch_latest + # Scan jsonschema versions py310-sphx_latest-attrs_latest-jsch_{3_0,3_1,3_2,4_0,4_1,dev} + # Earliest supported Python and lib versions all together py36-sphx_1_6_x-attrs_19_2-jsch_3_0 + # Spot matrix of early Python, Sphinx, attrs versions py3{7,8,9}-sphx_{1,2}_x-attrs_{19,20}_2-jsch_latest + # Test the specific Sphinx threshold cases where behavior changed py310-sphx_{2_3_1,2_4_0,3_2_1,3_3_0,3_4_0}-attrs_latest-jsch_latest + # Simple 'does the sdist install' check sdist_install + # Lints flake8 [testenv] commands= python --version pip list + # Want the tox *matrix* to ignore warnings since it's primarily + # a compatibility check. The defaults for bare pytest enable -Werror pytest {posargs:--nonloc -Wignore} deps= sphx_1_6_x: sphinx<1.7 From 6ac18727ec60ebfac1720613c9e5bffcdff3d9ff Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Wed, 2 Nov 2022 23:52:14 -0400 Subject: [PATCH 083/106] Tweak styles of docs theme --- doc/source/_static/css/custom.css | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/doc/source/_static/css/custom.css b/doc/source/_static/css/custom.css index a2471dd3..fbd460f0 100644 --- a/doc/source/_static/css/custom.css +++ b/doc/source/_static/css/custom.css @@ -1,16 +1,36 @@ +/* Lighten the header blue color */ div.wy-side-nav-search { background-color: #7ebbff; } +/* White version text in header */ div.version { color: #ffffff !important; font-weight: bolder !important; } -li.toctree-l1:not(.current) a { +/* Blue border around the search bar */ +form.wy-form input { + border: 3px solid #6eabef !important; +} + +/* + ul.current selects only the sidebar ul. Otherwise, + toctrees in the text get colored white, too +*/ +ul.current li.toctree-l1:not(.current) a { color: #f8f8f8 !important; } -form.wy-form input { - border: 3px solid #6eabef !important; +/* Increase font size for code object names in navbar toctree */ +a.reference.internal code.docutils.literal.notranslate { + font-size: 85%; } + +/* + Reduce margin at bottom of 'property' docs. + Too much vertical whitespace previously. +*/ +.rst-content dl.property { + margin-bottom: 10px !important; +} \ No newline at end of file From 28433a84674626357c773233fc88bedd4520628c Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Wed, 2 Nov 2022 23:52:48 -0400 Subject: [PATCH 084/106] Fix incorrect docstring in inventory.py Accidentally cargo-culted in a bunch of stuff about expand/contract args that are meaningless for the objects_rst property. --- src/sphobjinv/inventory.py | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/sphobjinv/inventory.py b/src/sphobjinv/inventory.py index 270481e4..af8810c1 100644 --- a/src/sphobjinv/inventory.py +++ b/src/sphobjinv/inventory.py @@ -277,35 +277,11 @@ def objects_rst(self): :class:`data.SuperDataObj.rst_fmt `. - Calling with both `expand` and `contract` as |True| is invalid. - - Parameters - ---------- - expand - - |bool| *(optional)* -- Return |str|\ s with any - :data:`~sphobjinv.data.SuperDataObj.uri` or - :data:`~sphobjinv.data.SuperDataObj.dispname` - abbreviations expanded - - contract - - |bool| *(optional)* -- Return |str|\ s with abbreviated - :data:`~sphobjinv.data.SuperDataObj.uri` and - :data:`~sphobjinv.data.SuperDataObj.dispname` values - Returns ------- obj_l - |list| of |str| - -- Inventory object data in reST-like format - - Raises - ------ - ValueError - - If both `expand` and `contract` are |True| + |list| of |str| -- Inventory object data in reST-like format """ return [_.as_rst for _ in self.objects] From 67cf1a2bf67b223c6bf0812da6ee4cad0857da5e Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Wed, 2 Nov 2022 23:53:42 -0400 Subject: [PATCH 085/106] Lengthen docstring for SuperDataObj.priority Template was rendering some of the API items oddly, apparently due to the text being quite short. Lengthening the text made it render as part of the vertical sequence, as expected. --- src/sphobjinv/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sphobjinv/data.py b/src/sphobjinv/data.py index 3674b26a..e17e4330 100644 --- a/src/sphobjinv/data.py +++ b/src/sphobjinv/data.py @@ -133,7 +133,7 @@ def role(self): @property @abstractmethod def priority(self): - r"""Object search priority\ |dag|.""" + r"""Object search priority, as handled internally by Sphinx\ |dag|.""" @property @abstractmethod From f67a130dc81d25ea2f3432879e0ea32c7c6d7c7c Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 5 Nov 2022 13:39:34 -0400 Subject: [PATCH 086/106] Tweak some docs language --- doc/source/index.rst | 10 ++++++---- doc/source/syntax.rst | 16 ++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/doc/source/index.rst b/doc/source/index.rst index e93c911f..aee4ebd0 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -63,7 +63,7 @@ and package managers, including: * OpenEuler: ``python-sphobjinv`` - * openSUSE: ``python-sphobjinv`` (`info `__) + * openSUSE: ``python-sphobjinv`` (`info `__) * Parabola: ``python-sphobjinv`` (`info `__) @@ -103,9 +103,11 @@ The project source repository is on GitHub: `bskinn/sphobjinv Indices and Tables ------------------ -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + * :ref:`genindex` + + * :ref:`modindex` + + * :ref:`search` .. raw:: html diff --git a/doc/source/syntax.rst b/doc/source/syntax.rst index f3bd1c53..1bb62e49 100644 --- a/doc/source/syntax.rst +++ b/doc/source/syntax.rst @@ -13,12 +13,16 @@ Based upon a quick ``git diff`` of the `Sphinx repository `__, it is thought to be valid for all Sphinx versions >=1.0b1 that make use of this "version 2" |objects.inv| format. -**NOTE** that the previous version of the syntax presented here has been -shown to be inaccurate (see :issue:`181`), in that it *is* -permitted for the |{name}|_ field to contain whitespace. -The descriptions below have been updated to reflect this and to provide -more detailed information on the constraints governing each field -of an |objects.inv| data line. +**NOTE** that previous versions of the syntax presented here have been +shown to be inaccurate: + + * It *is* permitted for the |{name}|_ field to contain whitespace (see :issue:`181`). + + * It *is* permitted for the |{role}|_ field to contain a colon (see :issue:`256`). + +The descriptions below have been updated to reflect this and to provide more +detailed information on the constraints governing each field of an |objects.inv| +data line. ---- From d01190c369d1ff07f9385be44c3185de6bfd633a Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 5 Nov 2022 13:39:58 -0400 Subject: [PATCH 087/106] Bump version to 2.3 --- src/sphobjinv/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sphobjinv/version.py b/src/sphobjinv/version.py index 211308cc..02ff1d84 100644 --- a/src/sphobjinv/version.py +++ b/src/sphobjinv/version.py @@ -25,4 +25,4 @@ """ -__version__ = "2.3.dev0" +__version__ = "2.3" From 52780e3d38a15028c91bb27c54509480aca2292a Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 5 Nov 2022 13:44:48 -0400 Subject: [PATCH 088/106] Reflow CONTRIBUTING.md --- CONTRIBUTING.md | 190 +++++++++++++++++++++++------------------------- 1 file changed, 92 insertions(+), 98 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e04d4e7..69fc0d4d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,8 +37,8 @@ Start by forking the repo and cloning locally: $ git clone https://github.com/{you}/sphobjinv ``` -Then, create a virtual environment for the project, -in whatever location you prefer. Any Python interpreter 3.6+ *should* work fine. +Then, create a virtual environment for the project, in whatever location you +prefer. Any Python interpreter 3.6+ *should* work fine. I prefer to use `virtualenv` and create in `./env`: @@ -80,8 +80,8 @@ as some of the tests interact with them: ## Working with git -There's no way I can fit a whole git tutorial in here, so this -just highlights a couple of key functionalities you'll need. +There's no way I can fit a whole git tutorial in here, so this just highlights a +couple of key functionalities you'll need. First, always hack on a bugfix or feature in a new branch: @@ -89,11 +89,11 @@ First, always hack on a bugfix or feature in a new branch: $ git checkout -b description-of-change ``` -This makes it a lot simpler to get your repo fork up to date -after `main` receives further commits. +This makes it a lot simpler to get your repo fork up to date after `main` +receives further commits. -To bring your fork's `main` up to date, you first need to -add the main repo as a new git remote (one-time task): +To bring your fork's `main` up to date, you first need to add the main repo as a +new git remote (one-time task): ``` $ git remote add upstream https://github.com/bskinn/sphobjinv @@ -111,47 +111,44 @@ $ git push # (should push to your fork without incident) ## Tests -`sphobjinv` uses the [`pytest`](https://github.com/pytest-dev/pytest) -framework for most of its automated tests. From a properly configured -virtual environment, a simple no-arguments invocation is all -that is required: +`sphobjinv` uses the [`pytest`](https://github.com/pytest-dev/pytest) framework +for most of its automated tests. From a properly configured virtual environment, +a simple no-arguments invocation is all that is required: ``` $ pytest ``` -The test suite defaults to running only local tests, -those that do **NOT** require network access. To include -the nonlocal tests, run with the `--nonloc` flag: +The test suite defaults to running only local tests, those that do **NOT** +require network access. To include the nonlocal tests, run with the `--nonloc` +flag: ``` $ pytest --nonloc ``` -When putting together a PR, at minimum, please add/augment the test suite -as necessary to maintain 100% test coverage. To the extent possible, -please go beyond this and add tests that check potential edge cases, -bad/malformed/invalid inputs, etc. For bugfixes, add one or more -focused regression tests that cover the bug behavior being fixed. +When putting together a PR, at minimum, please add/augment the test suite as +necessary to maintain 100% test coverage. To the extent possible, please go +beyond this and add tests that check potential edge cases, bad/malformed/invalid +inputs, etc. For bugfixes, add one or more focused regression tests that cover +the bug behavior being fixed. -PRs that add [xfail tests for existing bugs](https://blog.ganssle.io/articles/2021/11/pytest-xfail.html) +PRs that add +[xfail tests for existing bugs](https://blog.ganssle.io/articles/2021/11/pytest-xfail.html) are also welcomed. -There are some situations where it may make sense to use a -`# pragma: no cover` to ignore coverage on certain line(s) of code. -Please start a discussion in the issue or PR comments before -adding such a pragma. +There are some situations where it may make sense to use a `# pragma: no cover` +to ignore coverage on certain line(s) of code. Please start a discussion in the +issue or PR comments before adding such a pragma. -Note that while [`tox`](https://github.com/tox-dev/tox/) *is* -configured for the project, it is **not** set up to be an everyday test runner. -Instead, it's used to execute a matrix of test environments -checking for the compatibility of different Python and dependency -versions. You can run it if you want, but you'll need -working versions of all of Python 3.6 through 3.11 -installed and on `PATH` as `python3.6`, `python3.7`, etc. -The nonlocal test suite is run for each `tox` environment, so -it's best to use at most two parallel sub-processes to avoid oversaturating -your network bandwidth; e.g.: +Note that while [`tox`](https://github.com/tox-dev/tox/) *is* configured for the +project, it is **not** set up to be an everyday test runner. Instead, it's used +to execute a matrix of test environments checking for the compatibility of +different Python and dependency versions. You can run it if you want, but you'll +need working versions of all of Python 3.6 through 3.11 installed and on `PATH` +as `python3.6`, `python3.7`, etc. The nonlocal test suite is run for each `tox` +environment, so it's best to use at most two parallel sub-processes to avoid +oversaturating your network bandwidth; e.g.: ``` $ tox -rp2 @@ -161,8 +158,8 @@ $ tox -rp2 ## Linting The project uses a number of lints, which are checked using -[`flake8`](https://gitlab.com/pycqa/flake8) in CI. -To run the lints locally, it's easiest to use `tox`: +[`flake8`](https://gitlab.com/pycqa/flake8) in CI. To run the lints locally, +it's easiest to use `tox`: ``` $ tox -e flake8 @@ -170,15 +167,15 @@ $ tox -e flake8 In some limited circumstances, it may be necessary to add [`# noqa`](https://flake8.pycqa.org/en/stable/user/violations.html#in-line-ignoring-errors) -or [`per_file_ignores`](https://flake8.pycqa.org/en/stable/user/options.html#cmdoption-flake8-per-file-ignores) -exclusions to the `flake8` lints. -Please note these for discussion in an issue/PR comment -as soon as you think they might be needed. +or +[`per_file_ignores`](https://flake8.pycqa.org/en/stable/user/options.html#cmdoption-flake8-per-file-ignores) +exclusions to the `flake8` lints. Please note these for discussion in an +issue/PR comment as soon as you think they might be needed. -Additionally, the CI for pull requests is set up to check that all -modules, functions, classes and methods have docstrings -using the [`interrogate`](https://pypi.org/project/interrogate/) package. -There's a `tox` environment for running this check, also: +Additionally, the CI for pull requests is set up to check that all modules, +functions, classes and methods have docstrings using the +[`interrogate`](https://pypi.org/project/interrogate/) package. There's a `tox` +environment for running this check, also: ``` $ tox -e interrogate @@ -187,36 +184,33 @@ $ tox -e interrogate ## Type Hints -I'd like to [roll out typing](https://github.com/bskinn/sphobjinv/issues/132) -on the project at some point in the near future, and add -[`mypy`](https://github.com/python/mypy) checking to CI. -(This would be a great PR to put together, for anyone interested....) -For now, types on contributed code are welcomed, but optional. -Once the codebase is typed, though, they will be a required part of -any PR touching code. +I'd like to [roll out typing](https://github.com/bskinn/sphobjinv/issues/132) on +the project at some point in the near future, and add +[`mypy`](https://github.com/python/mypy) checking to CI. (This would be a great +PR to put together, for anyone interested....) For now, types on contributed +code are welcomed, but optional. Once the codebase is typed, though, they will +be a required part of any PR touching code. ## Documentation -All of the project documentation (except the README) is -generated via [Sphinx](https://github.com/sphinx-doc/sphinx), -and should be updated for (at minimum) any behavior changes -in the codebase. API changes should be documented in the -relevant docstring(s), and possibly in the prose portions -of the documentation as well. Please use the modified -[NumPy-style](https://numpydoc.readthedocs.io/en/latest/format.html) -formatting for docstrings that is already in use in the project. +All of the project documentation (except the README) is generated via +[Sphinx](https://github.com/sphinx-doc/sphinx), and should be updated for (at +minimum) any behavior changes in the codebase. API changes should be documented +in the relevant docstring(s), and possibly in the prose portions of the +documentation as well. Please use the modified +[NumPy-style](https://numpydoc.readthedocs.io/en/latest/format.html) formatting +for docstrings that is already in use in the project. A large number of reStructuredText substitutions are defined in the `rst_epilog` -setting within `conf.py`, to make the documentation source -more readable. Feel free to add more entries there. +setting within `conf.py`, to make the documentation source more readable. Feel +free to add more entries there. -To run any of the Sphinx builders, first change to the `/doc` directory -in the repository tree. In most cases, a plain `make html` invocation -is sufficient to build the docs properly, -as Sphinx does its best to detect which files were changed and -rebuild only the minimum portion of the documentation necessary. -If the docs seem not to be rendering correctly, try a clean build: +To run any of the Sphinx builders, first change to the `/doc` directory in the +repository tree. In most cases, a plain `make html` invocation is sufficient to +build the docs properly, as Sphinx does its best to detect which files were +changed and rebuild only the minimum portion of the documentation necessary. If +the docs seem not to be rendering correctly, try a clean build: ``` === Linux/Mac @@ -226,10 +220,10 @@ doc $ make clean html doc> make -Ea ``` -It's also a good idea to build the complete docs every once in a while with -its ['nitpicky' option](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-nitpicky), -in order to detect any broken cross-references, as these will fail -the [Azure CI pipeline](#continuous-integration): +It's also a good idea to build the complete docs every once in a while with its +['nitpicky' option](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-nitpicky), +in order to detect any broken cross-references, as these will fail the +[Azure CI pipeline](#continuous-integration): ``` === Linux/Mac @@ -239,49 +233,49 @@ doc $ O=-n make clean html doc> make html -Ean ``` -You can also run the doctests with `make doctest` -and the link validity checker with `make linkcheck`. +You can also run the doctests with `make doctest` and the link validity checker +with `make linkcheck`. ## Continuous Integration -Both Github Actions and Azure Pipelines are set up for the project, -and should run on any forks of the repository. +Both Github Actions and Azure Pipelines are set up for the project, and should +run on any forks of the repository. -Github Actions runs the test suite on Linux for Python 3.6 through 3.10, -as well as the `flake8` lints and the Sphinx doctests and link-validity testing, -and is configured to run on all commits. The workflow can be skipped -per-commit by including `[skip ci]` in the commit message. +Github Actions runs the test suite on Linux for Python 3.6 through 3.10, as well +as the `flake8` lints and the Sphinx doctests and link-validity testing, and is +configured to run on all commits. The workflow can be skipped per-commit by +including `[skip ci]` in the commit message. The Azure Pipelines CI runs an extensive matrix of cross-platform and -cross-Python-version tests, as well as numerous other checks. -Due to its length, it is configured to run only on release branches -and PRs to `main` or `stable`. It cannot be skipped. +cross-Python-version tests, as well as numerous other checks. Due to its length, +it is configured to run only on release branches and PRs to `main` or `stable`. +It cannot be skipped. ## CHANGELOG -The project [`CHANGELOG`](https://github.com/bskinn/sphobjinv/blob/main/CHANGELOG.md) -should be updated for the majority of contributions. No tooling is in place -(e.g., [`towncrier`](https://github.com/twisted/towncrier)) for automated collation -of news items into `CHANGELOG`; -all changes should be documented manually, directly in the `CHANGELOG`. +The project +[`CHANGELOG`](https://github.com/bskinn/sphobjinv/blob/main/CHANGELOG.md) should +be updated for the majority of contributions. No tooling is in place (e.g., +[`towncrier`](https://github.com/twisted/towncrier)) for automated collation of +news items into `CHANGELOG`; all changes should be documented manually, directly +in the `CHANGELOG`. Any PR that touches the project code *must* include a `CHANGELOG` entry. -Contributions that make changes just to the test suite should usually also include -a `CHANGELOG` entry, except for very minor or cosmetic changes. Other changes of note -(packaging/build tooling, test/lint tooling/plugins, tool settings, etc.) -may also warrant a `CHANGELOG` bullet, depending on the situation. -When in doubt, ask! +Contributions that make changes just to the test suite should usually also +include a `CHANGELOG` entry, except for very minor or cosmetic changes. Other +changes of note (packaging/build tooling, test/lint tooling/plugins, tool +settings, etc.) may also warrant a `CHANGELOG` bullet, depending on the +situation. When in doubt, ask! ## Issue & PR Templates -The project is configured with a PR template and a couple of -issue templates, to hopefully make it easier to provide all -the information needed to act on code contributions, bug reports, -and feature requests. If the templates don't fit the issue/PR -you want to create, though, then don't use them. +The project is configured with a PR template and a couple of issue templates, to +hopefully make it easier to provide all the information needed to act on code +contributions, bug reports, and feature requests. If the templates don't fit the +issue/PR you want to create, though, then don't use them. ## License From ed3ecc8cb765f15c53a9c292d5659bafc313ba61 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 5 Nov 2022 14:10:43 -0400 Subject: [PATCH 089/106] Fix np version in README, project ver in setup.py --- README.rst | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 4dbdec7c..d1b40d12 100644 --- a/README.rst +++ b/README.rst @@ -90,7 +90,7 @@ For external references, just find the API documentation wherever it lives on the web, and pass ``sphobjinv suggest`` a URL from within the documentation set with the ``--url/-u`` flag. For example, say I need to know how to cross-reference the ``linspace`` function from numpy (see -`here `__):: +`here `__):: $ sphobjinv suggest https://numpy.org/doc/1.23/reference/index.html linspace -su diff --git a/setup.py b/setup.py index f144ca89..56ccb7ea 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ exec(Path("src", "sphobjinv", "version.py").read_text(encoding="utf-8"), exec_ns) __version__ = exec_ns["__version__"] -version_override = "2.2" +version_override = None def readme(): From 6f8936977e614b22964ca1446bcd17c0813bbe11 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 5 Nov 2022 13:56:24 -0400 Subject: [PATCH 090/106] Replace author email across project Preferring Gmail vs MIT alum --- conftest.py | 2 +- setup.cfg | 2 +- src/sphobjinv/__init__.py | 2 +- src/sphobjinv/__main__.py | 2 +- src/sphobjinv/_vendored/__init__.py | 4 ++-- src/sphobjinv/_vendored/fuzzywuzzy/__init__.py | 2 +- src/sphobjinv/cli/__init__.py | 2 +- src/sphobjinv/cli/convert.py | 2 +- src/sphobjinv/cli/core.py | 2 +- src/sphobjinv/cli/load.py | 2 +- src/sphobjinv/cli/parser.py | 2 +- src/sphobjinv/cli/paths.py | 2 +- src/sphobjinv/cli/suggest.py | 2 +- src/sphobjinv/cli/ui.py | 2 +- src/sphobjinv/cli/write.py | 2 +- src/sphobjinv/data.py | 2 +- src/sphobjinv/enum.py | 2 +- src/sphobjinv/error.py | 2 +- src/sphobjinv/fileops.py | 2 +- src/sphobjinv/inventory.py | 2 +- src/sphobjinv/re.py | 2 +- src/sphobjinv/schema.py | 2 +- src/sphobjinv/version.py | 2 +- src/sphobjinv/zlib.py | 2 +- tests/test_api_fail.py | 2 +- tests/test_api_good.py | 2 +- tests/test_api_good_nonlocal.py | 2 +- tests/test_cli.py | 2 +- tests/test_cli_nonlocal.py | 2 +- tests/test_fixture.py | 2 +- tests/test_flake8_ext.py | 2 +- tests/test_intersphinx.py | 2 +- tests/test_readme.py | 2 +- tests/test_valid_objects.py | 2 +- 34 files changed, 35 insertions(+), 35 deletions(-) diff --git a/conftest.py b/conftest.py index 7f783a7f..e661a0d2 100644 --- a/conftest.py +++ b/conftest.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 diff --git a/setup.cfg b/setup.cfg index f48600a9..cab8eb0d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,7 +12,7 @@ license_files = LICENSE.txt platforms = any author = Brian Skinn -author_email = bskinn@alum.mit.edu +author_email = brian.skinn@gmail.com classifiers = License :: OSI Approved License :: OSI Approved :: MIT License diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index bfdf67be..f1623b7f 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 17 May 2016 diff --git a/src/sphobjinv/__main__.py b/src/sphobjinv/__main__.py index bbf9eb2d..6fd356c0 100644 --- a/src/sphobjinv/__main__.py +++ b/src/sphobjinv/__main__.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 15 May 2020 diff --git a/src/sphobjinv/_vendored/__init__.py b/src/sphobjinv/_vendored/__init__.py index 7dfb4e2b..749b6519 100644 --- a/src/sphobjinv/_vendored/__init__.py +++ b/src/sphobjinv/_vendored/__init__.py @@ -6,7 +6,7 @@ Subpackage marker module for vendored packages. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 11 Dec 2021 @@ -25,4 +25,4 @@ **Members** -""" \ No newline at end of file +""" diff --git a/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py b/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py index 2be667f6..b759a7cb 100644 --- a/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py +++ b/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py @@ -19,7 +19,7 @@ **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 11 Dec 2021 diff --git a/src/sphobjinv/cli/__init__.py b/src/sphobjinv/cli/__init__.py index 8037cfa8..3ff153e1 100644 --- a/src/sphobjinv/cli/__init__.py +++ b/src/sphobjinv/cli/__init__.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 15 Nov 2020 diff --git a/src/sphobjinv/cli/convert.py b/src/sphobjinv/cli/convert.py index 48c9f9b1..7687f694 100644 --- a/src/sphobjinv/cli/convert.py +++ b/src/sphobjinv/cli/convert.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Oct 2022 diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index b6a914f0..9d3cf7a5 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 15 Nov 2020 diff --git a/src/sphobjinv/cli/load.py b/src/sphobjinv/cli/load.py index c5105cd3..d2aecdbb 100644 --- a/src/sphobjinv/cli/load.py +++ b/src/sphobjinv/cli/load.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 17 Nov 2020 diff --git a/src/sphobjinv/cli/parser.py b/src/sphobjinv/cli/parser.py index 1e8798b3..cca6ef9c 100644 --- a/src/sphobjinv/cli/parser.py +++ b/src/sphobjinv/cli/parser.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 15 Nov 2020 diff --git a/src/sphobjinv/cli/paths.py b/src/sphobjinv/cli/paths.py index 5ed69b99..e4f97206 100644 --- a/src/sphobjinv/cli/paths.py +++ b/src/sphobjinv/cli/paths.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 19 Nov 2020 diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 80d41cea..78c3822d 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Oct 2022 diff --git a/src/sphobjinv/cli/ui.py b/src/sphobjinv/cli/ui.py index 21ee6959..8f5cc0a7 100644 --- a/src/sphobjinv/cli/ui.py +++ b/src/sphobjinv/cli/ui.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 19 Nov 2020 diff --git a/src/sphobjinv/cli/write.py b/src/sphobjinv/cli/write.py index 45386395..5d9f0f34 100644 --- a/src/sphobjinv/cli/write.py +++ b/src/sphobjinv/cli/write.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 19 Nov 2020 diff --git a/src/sphobjinv/data.py b/src/sphobjinv/data.py index e17e4330..ce8ae6c8 100644 --- a/src/sphobjinv/data.py +++ b/src/sphobjinv/data.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 7 Nov 2017 diff --git a/src/sphobjinv/enum.py b/src/sphobjinv/enum.py index 1128e0c2..63c79df5 100644 --- a/src/sphobjinv/enum.py +++ b/src/sphobjinv/enum.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 4 May 2019 diff --git a/src/sphobjinv/error.py b/src/sphobjinv/error.py index 939ac1ca..82e9a3e3 100644 --- a/src/sphobjinv/error.py +++ b/src/sphobjinv/error.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 5 Nov 2017 diff --git a/src/sphobjinv/fileops.py b/src/sphobjinv/fileops.py index c35d550a..d5d4fd07 100644 --- a/src/sphobjinv/fileops.py +++ b/src/sphobjinv/fileops.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 5 Nov 2017 diff --git a/src/sphobjinv/inventory.py b/src/sphobjinv/inventory.py index af8810c1..906940a7 100644 --- a/src/sphobjinv/inventory.py +++ b/src/sphobjinv/inventory.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 7 Dec 2017 diff --git a/src/sphobjinv/re.py b/src/sphobjinv/re.py index dfb7d203..b3a155a2 100644 --- a/src/sphobjinv/re.py +++ b/src/sphobjinv/re.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 5 Nov 2017 diff --git a/src/sphobjinv/schema.py b/src/sphobjinv/schema.py index 39119ca7..bd5106a2 100644 --- a/src/sphobjinv/schema.py +++ b/src/sphobjinv/schema.py @@ -5,7 +5,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 7 Dec 2017 diff --git a/src/sphobjinv/version.py b/src/sphobjinv/version.py index 02ff1d84..9218a16a 100644 --- a/src/sphobjinv/version.py +++ b/src/sphobjinv/version.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 18 Mar 2019 diff --git a/src/sphobjinv/zlib.py b/src/sphobjinv/zlib.py index 92a724fa..c0ecaa59 100644 --- a/src/sphobjinv/zlib.py +++ b/src/sphobjinv/zlib.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 5 Nov 2017 diff --git a/tests/test_api_fail.py b/tests/test_api_fail.py index 4296fb20..d45afa4d 100644 --- a/tests/test_api_fail.py +++ b/tests/test_api_fail.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 diff --git a/tests/test_api_good.py b/tests/test_api_good.py index 877d3763..1ee48e7d 100644 --- a/tests/test_api_good.py +++ b/tests/test_api_good.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 diff --git a/tests/test_api_good_nonlocal.py b/tests/test_api_good_nonlocal.py index e11163fe..a699c442 100644 --- a/tests/test_api_good_nonlocal.py +++ b/tests/test_api_good_nonlocal.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 21 Mar 2019 diff --git a/tests/test_cli.py b/tests/test_cli.py index cdfd4a47..2c3cc6a0 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 diff --git a/tests/test_cli_nonlocal.py b/tests/test_cli_nonlocal.py index 3861fff8..52d93d65 100644 --- a/tests/test_cli_nonlocal.py +++ b/tests/test_cli_nonlocal.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 diff --git a/tests/test_fixture.py b/tests/test_fixture.py index d93d906f..392149d3 100644 --- a/tests/test_fixture.py +++ b/tests/test_fixture.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 diff --git a/tests/test_flake8_ext.py b/tests/test_flake8_ext.py index a13fa20d..604c9705 100644 --- a/tests/test_flake8_ext.py +++ b/tests/test_flake8_ext.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 27 Apr 2019 diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 925f07cf..27968801 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 21 Jun 2022 diff --git a/tests/test_readme.py b/tests/test_readme.py index a512738e..0eab696c 100644 --- a/tests/test_readme.py +++ b/tests/test_readme.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 6 Aug 2018 diff --git a/tests/test_valid_objects.py b/tests/test_valid_objects.py index ce88c18e..8fc2df5f 100644 --- a/tests/test_valid_objects.py +++ b/tests/test_valid_objects.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 13 Feb 2021 From d9205f8a26e090a0c4a3132681200993bef032ad Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sat, 5 Nov 2022 15:14:05 -0400 Subject: [PATCH 091/106] Update CONTRIBUTING.md and add 3.11 to GH Actions --- .github/workflows/ci_tests.yml | 2 +- CONTRIBUTING.md | 41 +++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index f978e74c..18ea8d83 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -63,7 +63,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: ['3.6', '3.7', '3.8', '3.9'] + python: ['3.6', '3.7', '3.8', '3.9', '3.11'] if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 69fc0d4d..ee8a1715 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,14 +63,22 @@ The next step is to upgrade/install the development requirements: (sphobjinv) $ pip install -r requirements-dev.txt ``` -Then, install the pre-commit hooks: +Then, install the [`pre-commit`](https://pre-commit.com/) hooks: ``` (sphobjinv) $ pre-commit install ``` -Finally, you'll need to build the Sphinx docs, -as some of the tests interact with them: +One of the `pre-commit` hooks installed on the project is the hook from +[`black`](https://black.readthedocs.io/en/stable/). If you want to run `black` +independently from `pre-commit`, you'll need to install it separately: + +``` +(sphobjinv) $ pip install black +``` + +Finally, you'll need to build the Sphinx docs locally, as some of the tests +interact with them: ``` (sphobjinv) $ cd doc @@ -104,8 +112,8 @@ Then, any time you need to refresh the fork's `main`: ``` $ git fetch --all $ git checkout main -$ git merge upstream/main # (should merge without incident) -$ git push # (should push to your fork without incident) +$ git merge upstream/main # (should merge without incident) +$ git push # (should push to your fork without incident) ``` @@ -141,14 +149,14 @@ There are some situations where it may make sense to use a `# pragma: no cover` to ignore coverage on certain line(s) of code. Please start a discussion in the issue or PR comments before adding such a pragma. -Note that while [`tox`](https://github.com/tox-dev/tox/) *is* configured for the +Note that while [`tox`](https://tox.wiki/en/latest/) *is* configured for the project, it is **not** set up to be an everyday test runner. Instead, it's used -to execute a matrix of test environments checking for the compatibility of -different Python and dependency versions. You can run it if you want, but you'll -need working versions of all of Python 3.6 through 3.11 installed and on `PATH` -as `python3.6`, `python3.7`, etc. The nonlocal test suite is run for each `tox` -environment, so it's best to use at most two parallel sub-processes to avoid -oversaturating your network bandwidth; e.g.: +to execute an extensive matrix of test environments checking for the +compatibility of different Python and dependency versions. You can run it if you +want, but you'll need working versions of all of Python 3.6 through 3.11 +installed and on `PATH` as `python3.6`, `python3.7`, etc. The nonlocal test +suite is run for each `tox` environment, so it's best to use at most two +parallel sub-processes to avoid oversaturating your network bandwidth; e.g.: ``` $ tox -rp2 @@ -158,7 +166,7 @@ $ tox -rp2 ## Linting The project uses a number of lints, which are checked using -[`flake8`](https://gitlab.com/pycqa/flake8) in CI. To run the lints locally, +[`flake8`](https://flake8.pycqa.org/en/latest/) in CI. To run the lints locally, it's easiest to use `tox`: ``` @@ -242,7 +250,7 @@ with `make linkcheck`. Both Github Actions and Azure Pipelines are set up for the project, and should run on any forks of the repository. -Github Actions runs the test suite on Linux for Python 3.6 through 3.10, as well +Github Actions runs the test suite on Linux for Python 3.6 through 3.11, as well as the `flake8` lints and the Sphinx doctests and link-validity testing, and is configured to run on all commits. The workflow can be skipped per-commit by including `[skip ci]` in the commit message. @@ -250,7 +258,8 @@ including `[skip ci]` in the commit message. The Azure Pipelines CI runs an extensive matrix of cross-platform and cross-Python-version tests, as well as numerous other checks. Due to its length, it is configured to run only on release branches and PRs to `main` or `stable`. -It cannot be skipped. +Azure Pipelines now [also obeys `[skip ci]` +directives](https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/azure-repos-git?view=azure-devops&tabs=yaml#skipping-ci-for-individual-pushes). ## CHANGELOG @@ -260,7 +269,7 @@ The project be updated for the majority of contributions. No tooling is in place (e.g., [`towncrier`](https://github.com/twisted/towncrier)) for automated collation of news items into `CHANGELOG`; all changes should be documented manually, directly -in the `CHANGELOG`. +in the `CHANGELOG`. Please follow the format currently in use. Any PR that touches the project code *must* include a `CHANGELOG` entry. Contributions that make changes just to the test suite should usually also From f97c073ad772c9974ba54777e216a69feb4ccfed Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 6 Nov 2022 00:39:43 -0400 Subject: [PATCH 092/106] Add analytics --- doc/source/conf.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/source/conf.py b/doc/source/conf.py index 64664b40..15a51e22 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -314,6 +314,13 @@ def file_head(fn, *, head=None): # html_theme = "sphinx_rtd_theme" +# Configure theme + +html_theme_options = { + "analytics_id": "G-J2PQ1V8NHR", + "analytics_anonymize_ip": True, +} + # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". From f9aeefc8a8284c919a33a183b19452a9962d1ba4 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 6 Nov 2022 00:40:39 -0400 Subject: [PATCH 093/106] Add license to footer and re-style. --- doc/source/_static/css/custom.css | 13 ++++++++++++- doc/source/_templates/footer.html | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 doc/source/_templates/footer.html diff --git a/doc/source/_static/css/custom.css b/doc/source/_static/css/custom.css index fbd460f0..ed801b50 100644 --- a/doc/source/_static/css/custom.css +++ b/doc/source/_static/css/custom.css @@ -33,4 +33,15 @@ a.reference.internal code.docutils.literal.notranslate { */ .rst-content dl.property { margin-bottom: 10px !important; -} \ No newline at end of file +} + +/* + Reduced font size in footer +*/ +footer, footer div[role=contentinfo] p, footer p.footer-license { + font-size: 13px; +} + +footer p.footer-license { + line-height: 20px; +} diff --git a/doc/source/_templates/footer.html b/doc/source/_templates/footer.html new file mode 100644 index 00000000..6713e7af --- /dev/null +++ b/doc/source/_templates/footer.html @@ -0,0 +1,14 @@ +{% extends "!footer.html" %} + +{%-block extrafooter %} + +{{ super }} + +

+

+ +{% endblock %} From a8411ab15c5e678162950eb198b3dc0c181b572d Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 6 Nov 2022 20:40:20 -0500 Subject: [PATCH 094/106] Remove Google Analytics RtD already does its own lightweight analytics! --- doc/source/conf.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 15a51e22..64664b40 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -314,13 +314,6 @@ def file_head(fn, *, head=None): # html_theme = "sphinx_rtd_theme" -# Configure theme - -html_theme_options = { - "analytics_id": "G-J2PQ1V8NHR", - "analytics_anonymize_ip": True, -} - # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". From 3bc486bc333275b0e2182cd829da4b890590f8a2 Mon Sep 17 00:00:00 2001 From: Brian Skinn Date: Sun, 6 Nov 2022 20:41:49 -0500 Subject: [PATCH 095/106] Move logo attribution to extrafooter Super handy! [skip ci] --- doc/source/_templates/footer.html | 7 +++++++ doc/source/index.rst | 13 +------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/doc/source/_templates/footer.html b/doc/source/_templates/footer.html index 6713e7af..1ee7734e 100644 --- a/doc/source/_templates/footer.html +++ b/doc/source/_templates/footer.html @@ -5,6 +5,13 @@ {{ super }}

+ + +